mirror of
https://github.com/postgres/postgres.git
synced 2025-08-30 06:01:21 +03:00
Rework XLogReader callback system
Code review for0dc8ead463
, prompted by a bug closed by91c40548d5
. XLogReader's system for opening and closing segments had gotten too complicated, with callbacks being passed at both the XLogReaderAllocate level (read_page) as well as at the WALRead level (segment_open). This was confusing and hard to follow, so restructure things so that these callbacks are passed together at XLogReaderAllocate time, and add another callback to the set (segment_close) to make it a coherent whole. Also, ensure XLogReaderState is an argument to all the callbacks, so that they can grab at the ->private data if necessary. Document the whole arrangement more clearly. Author: Álvaro Herrera <alvherre@alvh.no-ip.org> Reviewed-by: Kyotaro Horiguchi <horikyota.ntt@gmail.com> Discussion: https://postgr.es/m/20200422175754.GA19858@alvherre.pgsql
This commit is contained in:
@@ -120,7 +120,7 @@ StartupDecodingContext(List *output_plugin_options,
|
||||
TransactionId xmin_horizon,
|
||||
bool need_full_snapshot,
|
||||
bool fast_forward,
|
||||
XLogPageReadCB read_page,
|
||||
XLogReaderRoutine *xl_routine,
|
||||
LogicalOutputPluginWriterPrepareWrite prepare_write,
|
||||
LogicalOutputPluginWriterWrite do_write,
|
||||
LogicalOutputPluginWriterUpdateProgress update_progress)
|
||||
@@ -169,7 +169,7 @@ StartupDecodingContext(List *output_plugin_options,
|
||||
|
||||
ctx->slot = slot;
|
||||
|
||||
ctx->reader = XLogReaderAllocate(wal_segment_size, NULL, read_page, ctx);
|
||||
ctx->reader = XLogReaderAllocate(wal_segment_size, NULL, xl_routine, ctx);
|
||||
if (!ctx->reader)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_OUT_OF_MEMORY),
|
||||
@@ -215,7 +215,8 @@ StartupDecodingContext(List *output_plugin_options,
|
||||
* Otherwise, we set for decoding to start from the given LSN without
|
||||
* marking WAL reserved beforehand. In that scenario, it's up to the
|
||||
* caller to guarantee that WAL remains available.
|
||||
* read_page, prepare_write, do_write, update_progress --
|
||||
* xl_routine -- XLogReaderRoutine for underlying XLogReader
|
||||
* prepare_write, do_write, update_progress --
|
||||
* callbacks that perform the use-case dependent, actual, work.
|
||||
*
|
||||
* Needs to be called while in a memory context that's at least as long lived
|
||||
@@ -230,7 +231,7 @@ CreateInitDecodingContext(char *plugin,
|
||||
List *output_plugin_options,
|
||||
bool need_full_snapshot,
|
||||
XLogRecPtr restart_lsn,
|
||||
XLogPageReadCB read_page,
|
||||
XLogReaderRoutine *xl_routine,
|
||||
LogicalOutputPluginWriterPrepareWrite prepare_write,
|
||||
LogicalOutputPluginWriterWrite do_write,
|
||||
LogicalOutputPluginWriterUpdateProgress update_progress)
|
||||
@@ -327,7 +328,7 @@ CreateInitDecodingContext(char *plugin,
|
||||
|
||||
ctx = StartupDecodingContext(NIL, restart_lsn, xmin_horizon,
|
||||
need_full_snapshot, false,
|
||||
read_page, prepare_write, do_write,
|
||||
xl_routine, prepare_write, do_write,
|
||||
update_progress);
|
||||
|
||||
/* call output plugin initialization callback */
|
||||
@@ -357,7 +358,10 @@ CreateInitDecodingContext(char *plugin,
|
||||
* fast_forward
|
||||
* bypass the generation of logical changes.
|
||||
*
|
||||
* read_page, prepare_write, do_write, update_progress
|
||||
* xl_routine
|
||||
* XLogReaderRoutine used by underlying xlogreader
|
||||
*
|
||||
* prepare_write, do_write, update_progress
|
||||
* callbacks that have to be filled to perform the use-case dependent,
|
||||
* actual work.
|
||||
*
|
||||
@@ -372,7 +376,7 @@ LogicalDecodingContext *
|
||||
CreateDecodingContext(XLogRecPtr start_lsn,
|
||||
List *output_plugin_options,
|
||||
bool fast_forward,
|
||||
XLogPageReadCB read_page,
|
||||
XLogReaderRoutine *xl_routine,
|
||||
LogicalOutputPluginWriterPrepareWrite prepare_write,
|
||||
LogicalOutputPluginWriterWrite do_write,
|
||||
LogicalOutputPluginWriterUpdateProgress update_progress)
|
||||
@@ -425,7 +429,7 @@ CreateDecodingContext(XLogRecPtr start_lsn,
|
||||
|
||||
ctx = StartupDecodingContext(output_plugin_options,
|
||||
start_lsn, InvalidTransactionId, false,
|
||||
fast_forward, read_page, prepare_write,
|
||||
fast_forward, xl_routine, prepare_write,
|
||||
do_write, update_progress);
|
||||
|
||||
/* call output plugin initialization callback */
|
||||
|
@@ -233,7 +233,9 @@ pg_logical_slot_get_changes_guts(FunctionCallInfo fcinfo, bool confirm, bool bin
|
||||
ctx = CreateDecodingContext(InvalidXLogRecPtr,
|
||||
options,
|
||||
false,
|
||||
read_local_xlog_page,
|
||||
XL_ROUTINE(.page_read = read_local_xlog_page,
|
||||
.segment_open = wal_segment_open,
|
||||
.segment_close = wal_segment_close),
|
||||
LogicalOutputPrepareWrite,
|
||||
LogicalOutputWrite, NULL);
|
||||
|
||||
|
@@ -152,8 +152,10 @@ create_logical_replication_slot(char *name, char *plugin,
|
||||
ctx = CreateInitDecodingContext(plugin, NIL,
|
||||
false, /* just catalogs is OK */
|
||||
restart_lsn,
|
||||
read_local_xlog_page, NULL, NULL,
|
||||
NULL);
|
||||
XL_ROUTINE(.page_read = read_local_xlog_page,
|
||||
.segment_open = wal_segment_open,
|
||||
.segment_close = wal_segment_close),
|
||||
NULL, NULL, NULL);
|
||||
|
||||
/*
|
||||
* If caller needs us to determine the decoding start point, do so now.
|
||||
@@ -464,7 +466,9 @@ pg_logical_replication_slot_advance(XLogRecPtr moveto)
|
||||
ctx = CreateDecodingContext(InvalidXLogRecPtr,
|
||||
NIL,
|
||||
true, /* fast_forward */
|
||||
read_local_xlog_page,
|
||||
XL_ROUTINE(.page_read = read_local_xlog_page,
|
||||
.segment_open = wal_segment_open,
|
||||
.segment_close = wal_segment_close),
|
||||
NULL, NULL, NULL);
|
||||
|
||||
/*
|
||||
|
@@ -54,8 +54,8 @@
|
||||
#include "access/transam.h"
|
||||
#include "access/xact.h"
|
||||
#include "access/xlog_internal.h"
|
||||
#include "access/xlogreader.h"
|
||||
#include "access/xlogutils.h"
|
||||
|
||||
#include "catalog/pg_authid.h"
|
||||
#include "catalog/pg_type.h"
|
||||
#include "commands/dbcommands.h"
|
||||
@@ -248,8 +248,8 @@ static void LagTrackerWrite(XLogRecPtr lsn, TimestampTz local_flush_time);
|
||||
static TimeOffset LagTrackerRead(int head, XLogRecPtr lsn, TimestampTz now);
|
||||
static bool TransactionIdInRecentPast(TransactionId xid, uint32 epoch);
|
||||
|
||||
static int WalSndSegmentOpen(XLogSegNo nextSegNo, WALSegmentContext *segcxt,
|
||||
TimeLineID *tli_p);
|
||||
static int WalSndSegmentOpen(XLogReaderState *state, XLogSegNo nextSegNo,
|
||||
WALSegmentContext *segcxt, TimeLineID *tli_p);
|
||||
static void UpdateSpillStats(LogicalDecodingContext *ctx);
|
||||
|
||||
|
||||
@@ -798,7 +798,8 @@ StartReplication(StartReplicationCmd *cmd)
|
||||
}
|
||||
|
||||
/*
|
||||
* read_page callback for logical decoding contexts, as a walsender process.
|
||||
* XLogReaderRoutine->page_read callback for logical decoding contexts, as a
|
||||
* walsender process.
|
||||
*
|
||||
* Inside the walsender we can do better than read_local_xlog_page,
|
||||
* which has to do a plain sleep/busy loop, because the walsender's latch gets
|
||||
@@ -832,7 +833,8 @@ logical_read_xlog_page(XLogReaderState *state, XLogRecPtr targetPagePtr, int req
|
||||
count = flushptr - targetPagePtr; /* part of the page available */
|
||||
|
||||
/* now actually read the data, we know it's there */
|
||||
if (!WALRead(cur_page,
|
||||
if (!WALRead(state,
|
||||
cur_page,
|
||||
targetPagePtr,
|
||||
XLOG_BLCKSZ,
|
||||
sendSeg->ws_tli, /* Pass the current TLI because only
|
||||
@@ -840,7 +842,6 @@ logical_read_xlog_page(XLogReaderState *state, XLogRecPtr targetPagePtr, int req
|
||||
* TLI is needed. */
|
||||
sendSeg,
|
||||
sendCxt,
|
||||
WalSndSegmentOpen,
|
||||
&errinfo))
|
||||
WALReadRaiseError(&errinfo);
|
||||
|
||||
@@ -1005,7 +1006,9 @@ CreateReplicationSlot(CreateReplicationSlotCmd *cmd)
|
||||
|
||||
ctx = CreateInitDecodingContext(cmd->plugin, NIL, need_full_snapshot,
|
||||
InvalidXLogRecPtr,
|
||||
logical_read_xlog_page,
|
||||
XL_ROUTINE(.page_read = logical_read_xlog_page,
|
||||
.segment_open = WalSndSegmentOpen,
|
||||
.segment_close = wal_segment_close),
|
||||
WalSndPrepareWrite, WalSndWriteData,
|
||||
WalSndUpdateProgress);
|
||||
|
||||
@@ -1168,7 +1171,9 @@ StartLogicalReplication(StartReplicationCmd *cmd)
|
||||
*/
|
||||
logical_decoding_ctx =
|
||||
CreateDecodingContext(cmd->startpoint, cmd->options, false,
|
||||
logical_read_xlog_page,
|
||||
XL_ROUTINE(.page_read = logical_read_xlog_page,
|
||||
.segment_open = WalSndSegmentOpen,
|
||||
.segment_close = wal_segment_close),
|
||||
WalSndPrepareWrite, WalSndWriteData,
|
||||
WalSndUpdateProgress);
|
||||
|
||||
@@ -2441,9 +2446,10 @@ WalSndKill(int code, Datum arg)
|
||||
SpinLockRelease(&walsnd->mutex);
|
||||
}
|
||||
|
||||
/* walsender's openSegment callback for WALRead */
|
||||
/* XLogReaderRoutine->segment_open callback */
|
||||
static int
|
||||
WalSndSegmentOpen(XLogSegNo nextSegNo, WALSegmentContext *segcxt,
|
||||
WalSndSegmentOpen(XLogReaderState *state,
|
||||
XLogSegNo nextSegNo, WALSegmentContext *segcxt,
|
||||
TimeLineID *tli_p)
|
||||
{
|
||||
char path[MAXPGPATH];
|
||||
@@ -2531,6 +2537,12 @@ XLogSendPhysical(void)
|
||||
Size nbytes;
|
||||
XLogSegNo segno;
|
||||
WALReadError errinfo;
|
||||
static XLogReaderState fake_xlogreader =
|
||||
{
|
||||
/* Fake xlogreader state for WALRead */
|
||||
.routine.segment_open = WalSndSegmentOpen,
|
||||
.routine.segment_close = wal_segment_close
|
||||
};
|
||||
|
||||
/* If requested switch the WAL sender to the stopping state. */
|
||||
if (got_STOPPING)
|
||||
@@ -2748,7 +2760,8 @@ XLogSendPhysical(void)
|
||||
enlargeStringInfo(&output_message, nbytes);
|
||||
|
||||
retry:
|
||||
if (!WALRead(&output_message.data[output_message.len],
|
||||
if (!WALRead(&fake_xlogreader,
|
||||
&output_message.data[output_message.len],
|
||||
startptr,
|
||||
nbytes,
|
||||
sendSeg->ws_tli, /* Pass the current TLI because only
|
||||
@@ -2756,7 +2769,6 @@ retry:
|
||||
* TLI is needed. */
|
||||
sendSeg,
|
||||
sendCxt,
|
||||
WalSndSegmentOpen,
|
||||
&errinfo))
|
||||
WALReadRaiseError(&errinfo);
|
||||
|
||||
|
Reference in New Issue
Block a user