1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-05 23:56:58 +03:00

Check slot->restart_lsn validity in a few more places

Lack of these checks could cause visible misbehavior, including
assertion failures.  This was missed in commit c6550776394e, whereby
restart_lsn becomes invalid when the size limit is exceeded.

Also reword some existing error messages, and add errdetail(), so that
the reported errors all match in spirit.

Author: Kyotaro Horiguchi <horikyota.ntt@gmail.com>
Reviewed-by: Álvaro Herrera <alvherre@alvh.no-ip.org>
Discussion: https://postgr.es/m/20200408.093710.447591748588426656.horikyota.ntt@gmail.com
This commit is contained in:
Alvaro Herrera 2020-04-28 20:39:04 -04:00
parent 52b164c5a0
commit d0abe78d84
No known key found for this signature in database
GPG Key ID: 1C20ACB9D5C564AE
4 changed files with 31 additions and 3 deletions

View File

@ -143,7 +143,8 @@ SELECT slot_name FROM pg_create_physical_replication_slot('regression_slot3');
SELECT pg_replication_slot_advance('regression_slot3', '0/0'); -- invalid LSN SELECT pg_replication_slot_advance('regression_slot3', '0/0'); -- invalid LSN
ERROR: invalid target WAL LSN ERROR: invalid target WAL LSN
SELECT pg_replication_slot_advance('regression_slot3', '0/1'); -- error SELECT pg_replication_slot_advance('regression_slot3', '0/1'); -- error
ERROR: cannot advance replication slot that has not previously reserved WAL ERROR: replication slot "regression_slot3" cannot be advanced
DETAIL: This slot has never previously reserved WAL, or has been invalidated.
SELECT pg_drop_replication_slot('regression_slot3'); SELECT pg_drop_replication_slot('regression_slot3');
pg_drop_replication_slot pg_drop_replication_slot
-------------------------- --------------------------

View File

@ -237,6 +237,19 @@ pg_logical_slot_get_changes_guts(FunctionCallInfo fcinfo, bool confirm, bool bin
LogicalOutputPrepareWrite, LogicalOutputPrepareWrite,
LogicalOutputWrite, NULL); LogicalOutputWrite, NULL);
/*
* After the sanity checks in CreateDecodingContext, make sure the
* restart_lsn is valid. Avoid "cannot get changes" wording in this
* errmsg because that'd be confusingly ambiguous about no changes
* being available.
*/
if (XLogRecPtrIsInvalid(MyReplicationSlot->data.restart_lsn))
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("can no longer get changes from replication slot \"%s\"",
NameStr(*name)),
errdetail("This slot has never previously reserved WAL, or has been invalidated.")));
MemoryContextSwitchTo(oldcontext); MemoryContextSwitchTo(oldcontext);
/* /*

View File

@ -598,7 +598,9 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
if (XLogRecPtrIsInvalid(MyReplicationSlot->data.restart_lsn)) if (XLogRecPtrIsInvalid(MyReplicationSlot->data.restart_lsn))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("cannot advance replication slot that has not previously reserved WAL"))); errmsg("replication slot \"%s\" cannot be advanced",
NameStr(*slotname)),
errdetail("This slot has never previously reserved WAL, or has been invalidated.")));
/* /*
* Check if the slot is not moving backwards. Physical slots rely simply * Check if the slot is not moving backwards. Physical slots rely simply

View File

@ -600,6 +600,12 @@ StartReplication(StartReplicationCmd *cmd)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("cannot use a logical replication slot for physical replication"))); errmsg("cannot use a logical replication slot for physical replication")));
/*
* We don't need to verify the slot's restart_lsn here; instead we
* rely on the caller requesting the starting point to use. If the
* WAL segment doesn't exist, we'll fail later.
*/
} }
/* /*
@ -1134,6 +1140,13 @@ StartLogicalReplication(StartReplicationCmd *cmd)
(void) ReplicationSlotAcquire(cmd->slotname, SAB_Error); (void) ReplicationSlotAcquire(cmd->slotname, SAB_Error);
if (XLogRecPtrIsInvalid(MyReplicationSlot->data.restart_lsn))
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("cannot read from logical replication slot \"%s\"",
cmd->slotname),
errdetail("This slot has been invalidated because it exceeded the maximum reserved size.")));
/* /*
* Force a disconnect, so that the decoding code doesn't need to care * Force a disconnect, so that the decoding code doesn't need to care
* about an eventual switch from running in recovery, to running in a * about an eventual switch from running in recovery, to running in a
@ -1159,7 +1172,6 @@ StartLogicalReplication(StartReplicationCmd *cmd)
WalSndPrepareWrite, WalSndWriteData, WalSndPrepareWrite, WalSndWriteData,
WalSndUpdateProgress); WalSndUpdateProgress);
WalSndSetState(WALSNDSTATE_CATCHUP); WalSndSetState(WALSNDSTATE_CATCHUP);
/* Send a CopyBothResponse message, and start streaming */ /* Send a CopyBothResponse message, and start streaming */