Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1w5I4t-0036BB-1n for pgsql-hackers@arkaria.postgresql.org; Wed, 25 Mar 2026 06:50:55 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1w5I4r-00CM7Z-36 for pgsql-hackers@arkaria.postgresql.org; Wed, 25 Mar 2026 06:50:54 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1w5I4r-00CM7N-1l for pgsql-hackers@lists.postgresql.org; Wed, 25 Mar 2026 06:50:54 +0000 Received: from mail-lf1-x129.google.com ([2a00:1450:4864:20::129]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.98.2) (envelope-from ) id 1w5I4q-00000000vKl-0UEQ for pgsql-hackers@postgresql.org; Wed, 25 Mar 2026 06:50:53 +0000 Received: by mail-lf1-x129.google.com with SMTP id 2adb3069b0e04-5a1307438ddso5021377e87.1 for ; Tue, 24 Mar 2026 23:50:51 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1774421450; cv=none; d=google.com; s=arc-20240605; b=enzSeMfyy2C8l5woVyboz7Kv2m/x64TdV5glw8Atdv4xV1sJq8rgGXJ8gmgO7mAUh1 Tuf8EgFHCcPZBkONDvQHsKFrx3OnSNb2/x4Of56A6btkqWbdUaVxptEzYSc+QKYQ8MOR PIzVCfi0CfqSpVOuJTb/LkVClGF7SpyItJPyeHTCXzfOxilLvnLDkZN55DNZGH7gm9a2 keMFa0CXP5C6q9J9cX+6i++bONG1lkw5Xzoxoy21RGAhqpbQapTEgI4HS540anyzt+0h Ftt9J8O8JW8brvlc829pXyKT6IStO2eEhXNWswvBZX45jmfJnKAeF8OkbQZ/QA1A6MkN TeFA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:dkim-signature; bh=V7tNT6N/h3Inv3OmtFC+jXCiqrcZy8YJ9idkKl/4dio=; fh=sWdm9TeEyvIloGBHbweTRMQulLtIjX6uQpBoVY2Z31o=; b=EMJTuuAf7MkX+LX02ignPWYil0kV9KlFtjW66toAZY9GlqfzcwhG+tePKT5/q867Ri RjMMLkb8p/WTb20wDrcL78df7Fxt3YTOUIufwuVJKNX4BhPY7TmrO4w0b/hBt3PgsjPv tiNrCgJIyWy8ZWBK4qcPaLUwd+qRsvVMiL8uG6k3oy+K/R889K6CUem/6UghTybWVj3h tCI82WX63rMvACsKqijNVHO0XmXfbwH2kB0dWI+F+ocpc5ymjNVfkFjUCYo6a2UBziSe wW7lajO9ubfQeL8XrDIHlKne1V45eUmFweMOCzrdu0dSdOvqlp4MQ8sujryaDXPKa3xB 90zQ==; darn=postgresql.org ARC-Authentication-Results: i=1; mx.google.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1774421450; x=1775026250; darn=postgresql.org; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:from:to:cc:subject:date :message-id:reply-to; bh=V7tNT6N/h3Inv3OmtFC+jXCiqrcZy8YJ9idkKl/4dio=; b=mfFA0zrf7Cs1YF/d/bP1GU95BFWtm9AfV2ds4WO0DVNU7itC5lRGFVYKnkDcnjT13j kwFIGQwl0hzfdSMbngKZWtb05CgysCcu48bls1Q/4L4qfphveBwJmfXz7oLtPqs4d0ty NHugpWzOwGSr1nX37xQAAcrVxBMnfnLfThDiUu4l3orRNYorBvEQjid4YoMqhQZvhUrE 6OlNqZ/8UX1XZkRnfqZSYbu3X4H3KIV1ZUw3DuDgzNSAV3fNJqBof4IkViQawAfts6ZD luvPNSA8qSauzrDkyc9lOqYyuAJbUoWvh8LrweIk32h96N0BQTqwz0GVJpDEr0KaZGWs ZXEA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1774421450; x=1775026250; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=V7tNT6N/h3Inv3OmtFC+jXCiqrcZy8YJ9idkKl/4dio=; b=PVEImuv3W2tH3Dej3kylYGcfiUeCZKdC5H9IiAdCLNMgclUsEBSYSK0QZ1Fw6aTHAD yn0HS3snatto9DOo891xN77Ob3I71ssPhT0NPjzS95yoG8vOv9X+t3tq5qewMmHnGwGZ yG5p3pj7rNdnhgahISf8tLtq4Sg7u/TNg+FLyL9qlf1/wvBzBYifXMkYrV5S71sTvhyG 0kXRvCzRJlUhynHFLnCd2lZ/IgcUMk7KTTmsP9vu/0WnI7PUWp4cmpwuSdpwCsw9EJwf Xgzu/GWWOqE4NscMYHqYiCsLoN46PHawnqj0tWazEQk3ZZ51hse1Kuehripq0veYKFAi KuQw== X-Forwarded-Encrypted: i=1; AJvYcCXhFKILMI8lQ85GsW+fjgrAevaMTIEZbtPjeURbvdhOSNJ5zbvPbQDJ+kuEfvO4Xp7t2ShNX7Y6dTYFLJPN@postgresql.org X-Gm-Message-State: AOJu0YwI+OpjAkWuOryXsBtx/Iql7R+N063J53LJabUrDax1OoQAoAhw g/weGD+baP+DdWah5lNdgKFYhl2QH+k+WnEKOUudPo9D5BS4MDZbnm4Qel6iE/iUGmHFKkq+XDz ps2wXvzijdYHuCpv+WY44lxiPyafx7Vo= X-Gm-Gg: ATEYQzwG0q5RxGnlNdGgDBbYNyy9W7c67o5p7X3m3Juuuv9ETdHxdDTNpF9ZMCBrcqe IOqBZUQ7zjDh8K7XWTb6ORjMvD6iFfxXwse/9mpNo2VB5qm9e/HR11vTAoCQ4kfOsXNaBBQmDer 1rnrWuK4UbWLGeL8DK+UuajG7BMXTKokdnhl4W+oph47U0osGUSwIXHpO21BW/bJCZPnR1x6j4f Q0G9XtxASs9ws2FuSnJPq5k7PIJo1tgTtJv8Gz5PL8usMheJWrvWOJ7/jjG+eyKQmJup+xrlCrN wNDTemEa X-Received: by 2002:ac2:4425:0:b0:5a2:9d61:f710 with SMTP id 2adb3069b0e04-5a29d61f72cmr411581e87.28.1774421450086; Tue, 24 Mar 2026 23:50:50 -0700 (PDT) MIME-Version: 1.0 References: In-Reply-To: From: Masahiko Sawada Date: Tue, 24 Mar 2026 23:50:13 -0700 X-Gm-Features: AQROBzDodqmO07UPYb07imWGaI9QAI06jiqTtZZ19ufZU9JRm7dpKydRWdLLxVk Message-ID: Subject: Re: Introduce XID age based replication slot invalidation To: Bharath Rupireddy Cc: SATYANARAYANA NARLAPURAM , "Hayato Kuroda (Fujitsu)" , John H , PostgreSQL-development Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk On Tue, Mar 24, 2026 at 2:42=E2=80=AFPM Bharath Rupireddy wrote: > > Hi, > > On Mon, Mar 23, 2026 at 4:36=E2=80=AFPM Masahiko Sawada wrote: > > > > I've studied the discussion on this thread and the patch. I understand > > the purpose of this feature and agree that it's useful especially in > > cases where orphaned (physical or logical) replication slots prevent > > the xmin from advancing and inactive_since based slot invalidation > > might not fit. > > > > And +1 for treating both the slot's xmin and catalog_xmin similarly > > with the single GUC. > > Thanks for reviewing the patch. > > > > >> I made the following design choice: try invalidating only once per > > > >> vacuum cycle, not per table. While this keeps the cost of checking > > > >> (incl. the XidGenLock contention) for invalidation to a minimum wh= en > > > >> there are a large number of tables and replication slots, it can b= e > > > >> less effective when individual tables/indexes are large. Invalidat= ing > > > >> during checkpoints can help to some extent with the large table/in= dex > > > >> cases. But I'm open to thoughts on this. > > > > > > > > It may not solve the intent when the vacuum cycle is longer, which = one can expect on a large database particularly when there is heavy bloat. > > > > > > This design choice boils down to the following: a database instance > > > having either 1/ a large number of small tables or 2/ large tables. > > > From my experience, I have seen both cases but mostly case 2 (others > > > can correct me). In this context, having an XID age based slot > > > invalidation check once per relation makes sense. However, I'm open t= o > > > more thoughts here. > > > > ISTM that checking the XID-based slot invalidation per table would be > > more bullet-proof and cover many cases. How about checking the > > XID-based slot invalidation opportunity only when the OldestXmin is > > older than the new GUC? For example, we can do this check in > > heap_vacuum_rel() based on the VacuumCutoffs returned by > > vacuum_get_cutoffs(). If we invalidate at least one slot for its XID, > > we can re-compute the OldestXmin. > > Agreed. Here's the patch that moves the XID-age based slot > invalidation check to vacuum_get_cutoffs. This has some nice > advantages: 1/ It makes the check once per table (to help with large > tables). 2/ It makes the check less costly since we rely on already > computed OldestXmin and nextXID values. 3/ It avoids the checkpointer > to do XID-age based slot invalidation which keeps the usage of this > GUC simple with no additional costs to the checkpointer - just the > vacuum (both vacuum command and autovacuum) does the invalidation when > needed. > > I moved the new tests to the existing TAP test file > t/019_replslot_limit.pl alongside other invalidation tests. > > I added detailed comments around InvalidateXIDAgedReplicationSlots and > slightly modified the docs. > > Please find the v3 patch for further review. Thank you for updating the patch. I think the patch is reasonably simple and can avoid unnecessary overheads well due to XID-based checks. Here are some comments: + /* + * Try to invalidate XID-aged replication slots that may interfere with + * vacuum's ability to freeze and remove dead tuples. Since OldestXmin + * already covers the slot xmin/catalog_xmin values, pass it as a + * preliminary check to avoid additional iteration over all the slots. + * + * If at least one slot was invalidated, recompute OldestXmin so that t= his + * vacuum benefits from the advanced horizon immediately. + */ + if (InvalidateXIDAgedReplicationSlots(cutoffs->OldestXmin, nextXID)) + { + cutoffs->OldestXmin =3D GetOldestNonRemovableTransactionId(rel); + Assert(TransactionIdIsNormal(cutoffs->OldestXmin)); + } vacuum_get_cutoff() is also called by VACUUM FULL, CLUSTER, and REPACK. I'm not sure that users would expect the slot invalidation also in these commands. I think it's better to leave vacuum_get_cutoff() a pure cutoff computation function and we can try to invalidate slots in heap_vacuum_rel(). It requires additional ReadNextTransactionId() but we can live with it, or we can make vacuum_get_cutoffs() return the nextXID as well (stored in *cutoffs). --- + /* ensure it's a "normal" XID, else TransactionIdPrecedes misbehaves */ + /* this can cause the limit to go backwards by 3, but that's OK */ + if (!TransactionIdIsNormal(cutoffXID)) + cutoffXID =3D FirstNormalTransactionId; + + if (TransactionIdPrecedes(oldestXmin, cutoffXID)) + { + invalidated =3D InvalidateObsoleteReplicationSlots(RS_INVAL_XID_AGE= , + 0, + InvalidOid, + InvalidTransaction= Id, + nextXID); + } I think it's better to check the procArray->replication_slot_xmin and procArray->replication_slot_catalog_xmin before iterating over each slot. Otherwise, we would end up checking every slot even when a long running transaction holds the oldestxmin back. --- + if (cutoffXID < FirstNormalTransactionId) + cutoffXID -=3D FirstNormalTransactionId; and + if (!TransactionIdIsNormal(cutoffXID)) + cutoffXID =3D FirstNormalTransactionId; These codes have the same comment but are doing a slightly different thing. I guess the latter is missing '-'? Regards, --=20 Masahiko Sawada Amazon Web Services: https://aws.amazon.com