Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.92) (envelope-from ) id 1jAAl0-0003vX-1e for pgsql-hackers@arkaria.postgresql.org; Fri, 06 Mar 2020 11:03:06 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.89) (envelope-from ) id 1jAAkx-0005Xk-UJ for pgsql-hackers@arkaria.postgresql.org; Fri, 06 Mar 2020 11:03:03 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1jAAkx-0005Xc-K1 for pgsql-hackers@lists.postgresql.org; Fri, 06 Mar 2020 11:03:03 +0000 Received: from cyclops.postgrespro.ru ([93.174.131.138] helo=mail.postgrespro.ru) by magus.postgresql.org with esmtp (Exim 4.92) (envelope-from ) id 1jAAkr-0002M8-6D for pgsql-hackers@postgresql.org; Fri, 06 Mar 2020 11:03:02 +0000 Received: from localhost (localhost [127.0.0.1]) by mail.postgrespro.ru (Postfix) with ESMTP id 7D4F621C210F; Fri, 6 Mar 2020 14:02:55 +0300 (MSK) X-Virus-Scanned: Debian amavisd-new at postgrespro.ru X-Spam-Flag: NO X-Spam-Score: 0 X-Spam-Level: X-Spam-Status: No, score=x tagged_above=-99 required=4 WHITELISTED tests=[] autolearn=unavailable Received: from ars-thinkpad (nat03-43-2.netorn.net [188.35.130.88]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mail.postgrespro.ru (Postfix) with ESMTPSA id E823521C1F83; Fri, 6 Mar 2020 14:02:54 +0300 (MSK) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=postgrespro.ru; s=mail; t=1583492575; bh=kuxM/lMLPQpQntQbkz2XXaboDddKX3yuAo8P9oMiGdA=; h=References:From:To:Cc:Subject:In-reply-to:Date; b=PpBEzX8E44MkIMWMJea59jJaSBThvH7Ak+bC9uEuxudTGLfCoI6Vp67JJBr/B4X42 Bmo8BwRonJSNgdOthZlvW4Chngd68ng4GVRbI45EfUpExYnU2R5DZsmfj39wdZ5rjs iF9GxKBJSPS99xUsgGAtj7Q7sLqKvF/IygIjD8Zs= References: <871rr3ohbo.fsf@ars-thinkpad> <87v9oelex6.fsf@ars-thinkpad> <87k1406sj7.fsf@ars-thinkpad> User-agent: mu4e 1.2.0; emacs 26.0.50 From: Arseny Sher To: Masahiko Sawada Cc: PostgreSQL Hackers , Alvaro Herrera Subject: Re: logical copy_replication_slot issues In-reply-to: <87k1406sj7.fsf@ars-thinkpad> Date: Fri, 06 Mar 2020 14:02:53 +0300 Message-ID: <87imjh7nky.fsf@ars-thinkpad> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk --=-=-= Content-Type: text/plain I wrote: > It looks good to me now. After lying for some time in my head it reminded me that CreateInitDecodingContext not only pegs the LSN, but also xmin, so attached makes a minor comment correction. While taking a look at the nearby code it seemed weird to me that GetOldestSafeDecodingTransactionId checks PGXACT->xid, not xmin. Don't want to investigate this at the moment though, and not for this thread. Also not for this thread, but I've noticed pg_copy_logical_replication_slot doesn't allow to change plugin name which is an omission in my view. It would be useful and trivial to do. -- cheers, arseny --=-=-= Content-Type: text/x-diff Content-Disposition: inline; filename=fix_copy_slot_v4.patch diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c index 2c9d5de6d9..da634bef0e 100644 --- a/src/backend/replication/slotfuncs.c +++ b/src/backend/replication/slotfuncs.c @@ -121,7 +121,8 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS) */ static void create_logical_replication_slot(char *name, char *plugin, - bool temporary, XLogRecPtr restart_lsn) + bool temporary, XLogRecPtr restart_lsn, + bool find_startpoint) { LogicalDecodingContext *ctx = NULL; @@ -139,16 +140,18 @@ create_logical_replication_slot(char *name, char *plugin, temporary ? RS_TEMPORARY : RS_EPHEMERAL); /* - * Create logical decoding context, to build the initial snapshot. + * Create logical decoding context to find start point or, if we don't + * need it, to 1) bump slot's restart_lsn and xmin 2) check plugin sanity. */ ctx = CreateInitDecodingContext(plugin, NIL, - false, /* do not build snapshot */ + false, /* do not build data snapshot */ restart_lsn, logical_read_local_xlog_page, NULL, NULL, NULL); /* build initial snapshot, might take a while */ - DecodingContextFindStartpoint(ctx); + if (find_startpoint) + DecodingContextFindStartpoint(ctx); /* don't need the decoding context anymore */ FreeDecodingContext(ctx); @@ -179,7 +182,8 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS) create_logical_replication_slot(NameStr(*name), NameStr(*plugin), temporary, - InvalidXLogRecPtr); + InvalidXLogRecPtr, + true); values[0] = NameGetDatum(&MyReplicationSlot->data.name); values[1] = LSNGetDatum(MyReplicationSlot->data.confirmed_flush); @@ -683,10 +687,19 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot) /* Create new slot and acquire it */ if (logical_slot) + { + /* + * WAL required for building snapshot could be removed as we haven't + * reserved WAL yet. So we create a new logical replication slot + * without building an initial snapshot. A reasonable start point for + * decoding will be provided by the source slot. + */ create_logical_replication_slot(NameStr(*dst_name), plugin, temporary, - src_restart_lsn); + src_restart_lsn, + false); + } else create_physical_replication_slot(NameStr(*dst_name), true, @@ -703,6 +716,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot) TransactionId copy_xmin; TransactionId copy_catalog_xmin; XLogRecPtr copy_restart_lsn; + XLogRecPtr copy_confirmed_flush; bool copy_islogical; char *copy_name; @@ -714,6 +728,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot) copy_xmin = src->data.xmin; copy_catalog_xmin = src->data.catalog_xmin; copy_restart_lsn = src->data.restart_lsn; + copy_confirmed_flush = src->data.confirmed_flush; /* for existence check */ copy_name = pstrdup(NameStr(src->data.name)); @@ -738,6 +753,13 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot) NameStr(*src_name)), errdetail("The source replication slot was modified incompatibly during the copy operation."))); + /* The source slot must have a consistent snapshot */ + if (src_islogical && XLogRecPtrIsInvalid(copy_confirmed_flush)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot copy a logical replication slot that doesn't have confirmed_flush_lsn"), + errhint("Retry when the source replication slot creation is finished."))); + /* Install copied values again */ SpinLockAcquire(&MyReplicationSlot->mutex); MyReplicationSlot->effective_xmin = copy_effective_xmin; @@ -746,6 +768,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot) MyReplicationSlot->data.xmin = copy_xmin; MyReplicationSlot->data.catalog_xmin = copy_catalog_xmin; MyReplicationSlot->data.restart_lsn = copy_restart_lsn; + MyReplicationSlot->data.confirmed_flush = copy_confirmed_flush; SpinLockRelease(&MyReplicationSlot->mutex); ReplicationSlotMarkDirty(); --=-=-=--