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.94.2) (envelope-from ) id 1vGJRA-00CEAU-E5 for pgsql-hackers@arkaria.postgresql.org; Tue, 04 Nov 2025 15:59:11 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.94.2) (envelope-from ) id 1vGJR6-00Eruv-Rk for pgsql-hackers@arkaria.postgresql.org; Tue, 04 Nov 2025 15:59:07 +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.94.2) (envelope-from ) id 1vGJR6-00Erun-FF for pgsql-hackers@lists.postgresql.org; Tue, 04 Nov 2025 15:59:07 +0000 Received: from mail-il1-x129.google.com ([2607:f8b0:4864:20::129]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.96) (envelope-from ) id 1vGJR3-005QZ4-2J for pgsql-hackers@lists.postgresql.org; Tue, 04 Nov 2025 15:59:06 +0000 Received: by mail-il1-x129.google.com with SMTP id e9e14a558f8ab-43323420387so9984655ab.2 for ; Tue, 04 Nov 2025 07:59:05 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1762271944; x=1762876744; darn=lists.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=QAWdxN+rD0aBPRDbFhfnZMGqJ3IUR/zIgzIYAcy+oFo=; b=MFjAnDO+hgjxMt+Pa021Js29PnQZSkTWi4PX/9e5cD0K/LWyYj5f8YxaC27THBZx5h 64S5P7XY43cKf0VLCfDrgsd8HruQL9K4STvk+MPfpCd1z3WoKOgLUuEcJ4QW+zeYNwIH WaSuehyBiuzAMJC0smeGGKChUzJ1YceTvg6m2LqY3pWsy2BQr/t/fKvBrMMt+NxWnMxn fv+JW+SHQE8wgWfWGFBZulmM0LN1BwWf1S/KnQzZv+hXKybnA8Srw4SXlL9PCIR2nEuG xGY/W0/wCz9tRF0b3RcC+XNw1ow/8KO/4ktc/AoiaXV51ALlfSlon87mvvJgxpupRj42 gnXA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1762271944; x=1762876744; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=QAWdxN+rD0aBPRDbFhfnZMGqJ3IUR/zIgzIYAcy+oFo=; b=ITvl7uBtJ93OdHhjkrZn4asrq8zM7Qercu6IkpOTl4qpl3GJH8SFR5oQwfUxDGdY6p H3WJiGNWxuE+iH0QxybvIYX80Kkzz17ULEWs5s8uVif6S3dnHORrur3fVfKdcP9kx1u6 CHWkzvflv+tAkujPMHt3ggH9Udpsig3sq5INxF50OxzkTojvP36jniGbAW2Y2Yd1G8OU d7cOKOt641MRjrRDKDrJUS6QmPvyzlPRosL6kp37K6d8r3Rkc7XwJYI/7QYvpUNFhZeG +BW5kHNtKREii+qvKz1StgFaNE+BlYeTGmkNhlavaAE3JAZJg6goJmrXMNMeyCHErlUW 83wQ== X-Gm-Message-State: AOJu0YwxS9J2IATPfPKVsaMReKLa8jD/2UkhiN7c9nI3R06klFNTrqRv ZBhT8tEJmwz/rsUo2bYZlwummrR2PcwCsGzVeoOAi4SLXTHA7JJUmnNkaTA+/cNFvizNv1A4qk7 zwWij+xOKs+BGyQfsDQsCnzVR/SsT504= X-Gm-Gg: ASbGncvBuKArXaJFAdPSX3Z+gsrW+pQparkyKFjVLUbyndvXigOwcBakxDMP4L/d/n7 S1OuDGh6A2OQr2HOKUqY4DGN8UUeD/HqITarWHQJ3CrOlLMofpL1QGAa5jRaE9mypP1EfHHKlg1 B0RnM6ZdCwEkmttW9QInQmyDUMWrbjabKvrhkT/sfyx4aUc/zQ1J63UpQbAPWMINpYCSMPCGq3r MUV5Pb7RUpZPWePlXuEMZtFkd0eLxY7h07SQ/fvk09LIOF9Z5El+iYDMlPlK47oqi1VOHy9saD3 b288tzVGrSL0iBli0Uc= X-Google-Smtp-Source: AGHT+IGriMEY3q52O/PVt7YIKep5K5V3VyUTkV7PYm4qqLBopuTfJGJWF5obE8KQG/eaxrGRJ4DfWdnXNLDe/TGwNs4= X-Received: by 2002:a05:6e02:4519:b0:433:2091:8a86 with SMTP id e9e14a558f8ab-43320918c46mr140661695ab.6.1762271944099; Tue, 04 Nov 2025 07:59:04 -0800 (PST) MIME-Version: 1.0 References: In-Reply-To: From: Fujii Masao Date: Wed, 5 Nov 2025 00:58:51 +0900 X-Gm-Features: AWmQ_bkbuz81qdkzV2KemdqIMYOqpk_yoGyzKArJ-hXkJRo0napLp6SHuuEerl4 Message-ID: Subject: Re: Report oldest xmin source when autovacuum cannot remove tuples To: Shinya Kato Cc: PostgreSQL Hackers 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 Fri, Oct 31, 2025 at 3:32=E2=80=AFPM Shinya Kato wrote: > > Hi hackers, > > I am proposing to add the reason for the oldest xmin to VACUUM logs. > This feature would be useful for identifying why dead tuples cannot be > removed, thereby helping to diagnose and prevent table bloat. +1 I like this idea. Thanks for working on this! > This PoC patch addresses this problem. The implementation now outputs > the reason for the oldest xmin and, where applicable, the backend PID. > This information was originally discarded when calculating the oldest > xmin horizon, and the computation required to retrieve these reasons > is considered reasonable. > > The patch is attached. What do you think? According to cfbot, the 010_autovacuum_oldest_xmin_reason regression test passes on some platforms but fails on others (see [1]), so it doesn't appear stable. When I set up a primary and standby with hot_standby_feedback enabled, then created an old prepared transaction expected to prevent dead tuples from being vacuumed, VACUUM VERBOSE reported "hot standby feedback" instead of "prepared transaction" as the oldest xmin source. This isn't a b= ug since both xmins are the same in this case. But it may be confusing? Would it be better to report "prepared transaction" in such cases? + case OLDESTXMIN_SOURCE_ACTIVE_TRANSACTION: + msgfmt =3D include_pid ? + _("oldest xmin source: active transaction (pid=3D%d)\n") : + _("oldest xmin source: active transaction\n"); + break; + case OLDESTXMIN_SOURCE_HOT_STANDBY_FEEDBACK: + msgfmt =3D include_pid ? + _("oldest xmin source: hot standby feedback (pid=3D%d)\n") : + _("oldest xmin source: hot standby feedback\n"); In these two cases, the PID should always be non-zero, so the message formats without (pid=3D%d) might not be necessary. + /* Identify what forced each of the horizons above. */ + OldestXminInfo shared_oldest_nonremovable_info; + OldestXminInfo catalog_oldest_nonremovable_info; + OldestXminInfo data_oldest_nonremovable_info; + OldestXminInfo temp_oldest_nonremovable_info; It might be good to add a comment explaining why we track sources only for these four oldest xmins, and not for others like oldest_considered_running. + TransactionId old; + TransactionId new_horizon; + + if (!TransactionIdIsValid(candidate)) + return; The TransactionIdIsValid(candidate) check may be redundant, since TransactionIdOlder(old, candidate) already performs the same validation. - switch (GlobalVisHorizonKindForRel(rel)) + kind =3D GlobalVisHorizonKindForRel(rel); + switch (kind) This change doesn't seem necessary. Regards, [1] https://cirrus-ci.com/task/6063548834512896 --=20 Fujii Masao