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.
|
|
|
|
*
|
|
|
|
*
|
2020-01-01 18:21:45 +01:00
|
|
|
* Portions Copyright (c) 1996-2020, 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.h"
|
|
|
|
#include "access/xlog_internal.h"
|
|
|
|
#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
|
|
|
/*
|
|
|
|
* Store label file and tablespace map during non-exclusive backups.
|
|
|
|
*/
|
|
|
|
static StringInfo label_file;
|
|
|
|
static StringInfo tblspc_map_file;
|
|
|
|
|
2011-11-04 10:37:17 +01:00
|
|
|
/*
|
|
|
|
* pg_start_backup: set up for taking an on-line backup dump
|
|
|
|
*
|
|
|
|
* 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
|
|
|
|
pg_start_backup(PG_FUNCTION_ARGS)
|
|
|
|
{
|
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);
|
2016-04-05 20:03:49 +02:00
|
|
|
bool exclusive = PG_GETARG_BOOL(2);
|
2011-11-04 10:37:17 +01:00
|
|
|
char *backupidstr;
|
|
|
|
XLogRecPtr startpoint;
|
2017-03-24 11:53:40 +01:00
|
|
|
SessionBackupState status = get_backup_status();
|
2011-11-04 10:37:17 +01:00
|
|
|
|
|
|
|
backupidstr = text_to_cstring(backupid);
|
|
|
|
|
2017-03-24 11:53:40 +01:00
|
|
|
if (status == SESSION_BACKUP_NON_EXCLUSIVE)
|
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")));
|
|
|
|
|
|
|
|
if (exclusive)
|
|
|
|
{
|
|
|
|
startpoint = do_pg_start_backup(backupidstr, fast, NULL, NULL,
|
2017-12-05 00:37:54 +01:00
|
|
|
NULL, NULL, false, true);
|
2016-04-05 20:03:49 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
MemoryContext oldcontext;
|
|
|
|
|
|
|
|
/*
|
2016-06-10 00:02:36 +02:00
|
|
|
* Label file and tablespace map file need to be long-lived, since
|
|
|
|
* they are read in pg_stop_backup.
|
2016-04-05 20:03:49 +02:00
|
|
|
*/
|
|
|
|
oldcontext = MemoryContextSwitchTo(TopMemoryContext);
|
|
|
|
label_file = makeStringInfo();
|
|
|
|
tblspc_map_file = makeStringInfo();
|
|
|
|
MemoryContextSwitchTo(oldcontext);
|
|
|
|
|
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
|
|
|
register_persistent_abort_backup_handler();
|
|
|
|
|
2016-04-05 20:03:49 +02:00
|
|
|
startpoint = do_pg_start_backup(backupidstr, fast, NULL, label_file,
|
2017-12-05 00:37:54 +01:00
|
|
|
NULL, tblspc_map_file, false, true);
|
2016-04-05 20:03:49 +02:00
|
|
|
}
|
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
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* pg_stop_backup: finish taking an on-line backup dump
|
|
|
|
*
|
|
|
|
* We write an end-of-backup WAL record, and remove the backup label file
|
2016-10-20 17:24:37 +02:00
|
|
|
* created by pg_start_backup, creating a backup history file in pg_wal
|
2011-11-04 10:37:17 +01:00
|
|
|
* instead (whence it will immediately be archived). The backup history file
|
|
|
|
* contains the same info found in the label file, plus the backup-end time
|
|
|
|
* and WAL location. Before 9.0, the backup-end time was read from the backup
|
|
|
|
* history file at the beginning of archive recovery, but we now use the WAL
|
|
|
|
* record for that and the file is for informational and debug purposes only.
|
|
|
|
*
|
|
|
|
* Note: different from CancelBackup which just cancels online backup mode.
|
2016-04-05 20:03:49 +02:00
|
|
|
*
|
|
|
|
* Note: this version is only called to stop an exclusive backup. The function
|
2016-06-10 00:02:36 +02:00
|
|
|
* pg_stop_backup_v2 (overloaded as pg_stop_backup in SQL) is called to
|
|
|
|
* stop non-exclusive backups.
|
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_stop_backup(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
XLogRecPtr stoppoint;
|
2017-03-24 11:53:40 +01:00
|
|
|
SessionBackupState status = get_backup_status();
|
2011-11-04 10:37:17 +01:00
|
|
|
|
2017-03-24 11:53:40 +01:00
|
|
|
if (status == SESSION_BACKUP_NON_EXCLUSIVE)
|
2016-04-05 20:03:49 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
|
|
|
errmsg("non-exclusive backup in progress"),
|
2016-06-07 20:18:08 +02:00
|
|
|
errhint("Did you mean to use pg_stop_backup('f')?")));
|
2016-04-05 20:03:49 +02:00
|
|
|
|
|
|
|
/*
|
2016-06-10 00:02:36 +02:00
|
|
|
* Exclusive backups were typically started in a different connection, so
|
2017-03-24 11:53:40 +01:00
|
|
|
* don't try to verify that status of backup is set to
|
|
|
|
* SESSION_BACKUP_EXCLUSIVE in this function. Actual verification that an
|
2017-05-17 22:31:56 +02:00
|
|
|
* exclusive backup is in fact running is handled inside
|
|
|
|
* do_pg_stop_backup.
|
2016-04-05 20:03:49 +02:00
|
|
|
*/
|
Make pg_receivexlog and pg_basebackup -X stream work across timeline switches.
This mirrors the changes done earlier to the server in standby mode. When
receivelog reaches the end of a timeline, as reported by the server, it
fetches the timeline history file of the next timeline, and restarts
streaming from the new timeline by issuing a new START_STREAMING command.
When pg_receivexlog crosses a timeline, it leaves the .partial suffix on the
last segment on the old timeline. This helps you to tell apart a partial
segment left in the directory because of a timeline switch, and a completed
segment. If you just follow a single server, it won't make a difference, but
it can be significant in more complicated scenarios where new WAL is still
generated on the old timeline.
This includes two small changes to the streaming replication protocol:
First, when you reach the end of timeline while streaming, the server now
sends the TLI of the next timeline in the server's history to the client.
pg_receivexlog uses that as the next timeline, so that it doesn't need to
parse the timeline history file like a standby server does. Second, when
BASE_BACKUP command sends the begin and end WAL positions, it now also sends
the timeline IDs corresponding the positions.
2013-01-17 19:23:00 +01:00
|
|
|
stoppoint = do_pg_stop_backup(NULL, true, NULL);
|
2011-11-04 10:37:17 +01:00
|
|
|
|
2014-02-19 17:13:44 +01:00
|
|
|
PG_RETURN_LSN(stoppoint);
|
2011-11-04 10:37:17 +01:00
|
|
|
}
|
|
|
|
|
2016-04-05 20:03:49 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* pg_stop_backup_v2: finish taking exclusive or nonexclusive on-line backup.
|
|
|
|
*
|
|
|
|
* Works the same as pg_stop_backup, except for non-exclusive backups it returns
|
|
|
|
* the backup label and tablespace map files as text fields in as part of the
|
|
|
|
* resultset.
|
2016-04-07 03:45:32 +02:00
|
|
|
*
|
2017-03-23 04:44:58 +01:00
|
|
|
* The first parameter (variable 'exclusive') allows the user to tell us if
|
|
|
|
* this is an exclusive or a non-exclusive backup.
|
|
|
|
*
|
2017-06-17 10:17:01 +02:00
|
|
|
* The second 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
|
|
|
|
pg_stop_backup_v2(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2016-06-10 00:02:36 +02:00
|
|
|
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
|
|
|
|
TupleDesc tupdesc;
|
2016-04-05 20:03:49 +02:00
|
|
|
Tuplestorestate *tupstore;
|
2016-06-10 00:02:36 +02:00
|
|
|
MemoryContext per_query_ctx;
|
|
|
|
MemoryContext oldcontext;
|
|
|
|
Datum values[3];
|
|
|
|
bool nulls[3];
|
2016-04-05 20:03:49 +02:00
|
|
|
|
2016-06-10 00:02:36 +02:00
|
|
|
bool exclusive = PG_GETARG_BOOL(0);
|
2017-03-23 04:44:58 +01:00
|
|
|
bool waitforarchive = PG_GETARG_BOOL(1);
|
2016-06-10 00:02:36 +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
|
|
|
|
|
|
|
/* check to see if caller supports us returning a tuplestore */
|
|
|
|
if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("set-valued function called in context that cannot accept a set")));
|
|
|
|
if (!(rsinfo->allowedModes & SFRM_Materialize))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
2019-12-24 16:37:13 +01:00
|
|
|
errmsg("materialize mode required, but it is not allowed in this context")));
|
2016-04-05 20:03:49 +02:00
|
|
|
|
|
|
|
/* Build a tuple descriptor for our result type */
|
|
|
|
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
|
|
|
|
elog(ERROR, "return type must be a row type");
|
|
|
|
|
|
|
|
per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
|
|
|
|
oldcontext = MemoryContextSwitchTo(per_query_ctx);
|
|
|
|
|
|
|
|
tupstore = tuplestore_begin_heap(true, false, work_mem);
|
|
|
|
rsinfo->returnMode = SFRM_Materialize;
|
|
|
|
rsinfo->setResult = tupstore;
|
|
|
|
rsinfo->setDesc = tupdesc;
|
|
|
|
|
|
|
|
MemoryContextSwitchTo(oldcontext);
|
|
|
|
|
|
|
|
MemSet(values, 0, sizeof(values));
|
|
|
|
MemSet(nulls, 0, sizeof(nulls));
|
|
|
|
|
|
|
|
if (exclusive)
|
|
|
|
{
|
2017-03-24 11:53:40 +01:00
|
|
|
if (status == SESSION_BACKUP_NON_EXCLUSIVE)
|
2016-04-05 20:03:49 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
|
|
|
errmsg("non-exclusive backup in progress"),
|
2016-06-07 20:18:08 +02:00
|
|
|
errhint("Did you mean to use pg_stop_backup('f')?")));
|
2016-04-05 20:03:49 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Stop the exclusive backup, and since we're in an exclusive backup
|
|
|
|
* return NULL for both backup_label and tablespace_map.
|
|
|
|
*/
|
2017-03-23 04:44:58 +01:00
|
|
|
stoppoint = do_pg_stop_backup(NULL, waitforarchive, NULL);
|
2016-04-05 20:03:49 +02:00
|
|
|
|
|
|
|
nulls[1] = true;
|
|
|
|
nulls[2] = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-03-24 11:53:40 +01:00
|
|
|
if (status != SESSION_BACKUP_NON_EXCLUSIVE)
|
2016-04-05 20:03:49 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
|
|
|
errmsg("non-exclusive backup is not in progress"),
|
2016-06-07 20:18:08 +02:00
|
|
|
errhint("Did you mean to use pg_stop_backup('t')?")));
|
2016-04-05 20:03:49 +02:00
|
|
|
|
|
|
|
/*
|
2016-06-10 00:02:36 +02:00
|
|
|
* Stop the non-exclusive backup. Return a copy of the backup label
|
|
|
|
* and tablespace map so they can be written to disk by the caller.
|
2016-04-05 20:03:49 +02:00
|
|
|
*/
|
2017-03-23 04:44:58 +01:00
|
|
|
stoppoint = do_pg_stop_backup(label_file->data, waitforarchive, NULL);
|
2016-04-05 20:03:49 +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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Stoppoint is included on both exclusive and nonexclusive backups */
|
2016-06-10 00:02:36 +02:00
|
|
|
values[0] = LSNGetDatum(stoppoint);
|
2016-04-05 20:03:49 +02:00
|
|
|
|
|
|
|
tuplestore_putvalues(tupstore, tupdesc, values, nulls);
|
2019-08-19 09:21:39 +02:00
|
|
|
tuplestore_donestoring(tupstore);
|
2016-04-05 20:03:49 +02:00
|
|
|
|
|
|
|
return (Datum) 0;
|
|
|
|
}
|
|
|
|
|
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),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Report the current WAL write location (same format as pg_start_backup etc)
|
|
|
|
*
|
|
|
|
* 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
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Report the current WAL insert location (same format as pg_start_backup etc)
|
|
|
|
*
|
|
|
|
* 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
|
|
|
/*
|
|
|
|
* Report the current WAL flush location (same format as pg_start_backup etc)
|
|
|
|
*
|
|
|
|
* 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.")));
|
|
|
|
|
|
|
|
current_recptr = GetFlushRecPtr();
|
|
|
|
|
|
|
|
PG_RETURN_LSN(current_recptr);
|
|
|
|
}
|
|
|
|
|
2011-11-04 10:37:17 +01:00
|
|
|
/*
|
|
|
|
* Report the last WAL receive location (same format as pg_start_backup etc)
|
|
|
|
*
|
|
|
|
* 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
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Report the last WAL replay location (same format as pg_start_backup etc)
|
|
|
|
*
|
|
|
|
* 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,
|
2017-06-09 20:04:22 +02:00
|
|
|
* such as is returned by pg_stop_backup() 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);
|
|
|
|
XLogFileName(xlogfilename, ThisTimeLineID, 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,
|
2017-06-09 20:04:22 +02:00
|
|
|
* such as is returned by pg_stop_backup() 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);
|
|
|
|
XLogFileName(xlogfilename, ThisTimeLineID, xlogsegno, wal_segment_size);
|
2011-11-04 10:37:17 +01:00
|
|
|
|
|
|
|
PG_RETURN_TEXT_P(cstring_to_text(xlogfilename));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2017-02-09 21:10:09 +01:00
|
|
|
* pg_wal_replay_pause - pause 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_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);
|
|
|
|
|
|
|
|
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.")));
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(RecoveryIsPaused());
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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-05-06 18:12:18 +02: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
|
|
|
|
|
|
|
/*
|
|
|
|
* Returns bool with current on-line backup mode, a global state.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
pg_is_in_backup(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
PG_RETURN_BOOL(BackupInProgress());
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Returns start time of an online exclusive backup.
|
|
|
|
*
|
|
|
|
* When there's no exclusive backup in progress, the function
|
|
|
|
* returns NULL.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
pg_backup_start_time(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Datum xtime;
|
|
|
|
FILE *lfp;
|
|
|
|
char fline[MAXPGPATH];
|
|
|
|
char backup_start_time[30];
|
|
|
|
|
|
|
|
/*
|
|
|
|
* See if label file is present
|
|
|
|
*/
|
|
|
|
lfp = AllocateFile(BACKUP_LABEL_FILE, "r");
|
|
|
|
if (lfp == NULL)
|
|
|
|
{
|
|
|
|
if (errno != ENOENT)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode_for_file_access(),
|
|
|
|
errmsg("could not read file \"%s\": %m",
|
2013-05-29 22:58:43 +02:00
|
|
|
BACKUP_LABEL_FILE)));
|
2012-06-14 19:25:43 +02:00
|
|
|
PG_RETURN_NULL();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2013-12-13 18:58:48 +01:00
|
|
|
* Parse the file to find the START TIME line.
|
2012-06-14 19:25:43 +02:00
|
|
|
*/
|
|
|
|
backup_start_time[0] = '\0';
|
|
|
|
while (fgets(fline, sizeof(fline), lfp) != NULL)
|
|
|
|
{
|
|
|
|
if (sscanf(fline, "START TIME: %25[^\n]\n", backup_start_time) == 1)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2012-06-14 21:20:08 +02:00
|
|
|
/* Check for a read error. */
|
|
|
|
if (ferror(lfp))
|
2012-06-14 19:25:43 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode_for_file_access(),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
errmsg("could not read file \"%s\": %m", BACKUP_LABEL_FILE)));
|
2012-06-14 19:25:43 +02:00
|
|
|
|
2012-06-14 21:20:08 +02:00
|
|
|
/* Close the backup label file. */
|
|
|
|
if (FreeFile(lfp))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode_for_file_access(),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
errmsg("could not close file \"%s\": %m", BACKUP_LABEL_FILE)));
|
2012-06-14 21:20:08 +02:00
|
|
|
|
2012-06-14 19:25:43 +02:00
|
|
|
if (strlen(backup_start_time) == 0)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
|
|
|
errmsg("invalid data in file \"%s\"", BACKUP_LABEL_FILE)));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Convert the time string read from file to TimestampTz form.
|
|
|
|
*/
|
|
|
|
xtime = DirectFunctionCall3(timestamptz_in,
|
|
|
|
CStringGetDatum(backup_start_time),
|
|
|
|
ObjectIdGetDatum(InvalidOid),
|
|
|
|
Int32GetDatum(-1));
|
|
|
|
|
|
|
|
PG_RETURN_DATUM(xtime);
|
|
|
|
}
|
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,
|
|
|
|
(errmsg("server did not promote within %d seconds", wait_seconds)));
|
|
|
|
PG_RETURN_BOOL(false);
|
|
|
|
}
|