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 1vO0pb-005sk2-2N for pgsql-hackers@arkaria.postgresql.org; Tue, 25 Nov 2025 21:44:15 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1vO0pa-00Bzx6-1H for pgsql-hackers@arkaria.postgresql.org; Tue, 25 Nov 2025 21:44:14 +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 1vO0pZ-00Bzwy-38 for pgsql-hackers@lists.postgresql.org; Tue, 25 Nov 2025 21:44:14 +0000 Received: from mail-ed1-x534.google.com ([2a00:1450:4864:20::534]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.96) (envelope-from ) id 1vO0pX-001SjO-1u for pgsql-hackers@lists.postgresql.org; Tue, 25 Nov 2025 21:44:13 +0000 Received: by mail-ed1-x534.google.com with SMTP id 4fb4d7f45d1cf-644fcafdce9so9432929a12.1 for ; Tue, 25 Nov 2025 13:44:11 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1764107051; x=1764711851; 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=tJrbtW4MwnLdUy6EjzoLP0k52iOAJqQuYx4qjE/eSUI=; b=FlMxdvKdyKXkOZXamSMlx/9+TYw2zkA0FwBVP43Ihh9GIsBPht/OvjUt8AuinPjkQn PGuqUHbdRIZmeWm7tN4jwbq4SXMnCgPRfpOC5HSOiDK/b4w8NBz3TDRFLMnJaTN1DKGI 7ot+jtswrUNtr0rVEBKHOp848TKHyttUP1tDOWSoFlKdjWuHeUggMzv4alqVVcGF7pM6 C4b3VZpH689b+315DkEzUH72bpJv6dE4fH86vDWUOJU7x0JLbth37KPMG0qqr+2lILVc KKyq0gKRvp0Othw39US5tWxt+2KlfBg5Y4gFUhnHyerba9UHplC3PkYJ+5ll2RcuVvma /8vg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1764107051; x=1764711851; 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=tJrbtW4MwnLdUy6EjzoLP0k52iOAJqQuYx4qjE/eSUI=; b=s+95syI2NRyETIj05PHp5dwsKDKnkESWRZ0rpUf/hZ8uo5fuXQM6uuhj6SR0O2OkNH 4S9n3dhTMkKbKtGos8OFkfo9cDFmP0RI0NvamDXYCHOCygoFK6c/LRrrxXITwxZ7/ndc 83nBvs0rE4OzRhUrG2m0I+hhp05VkdNKsKxc8uoDvY3AGbKY29NEHL2Ddl5iJHnJ+vBU yJ73afkhk8zIDV4lcEvNKWH4rvnLikP04WYZy+ctVFcUfogOWPnHCkfOi5RprLRjAsdr KMjT3XDg03kuuQUQp48g1LrQagf0Tfi96hr3R8VZj5gj3rM0/2YKo+mck0RkqYySC08q J8dw== X-Forwarded-Encrypted: i=1; AJvYcCU7DlUCQIfwYYF1CxVOmVOL+aXRAdSOxZlWr1u7wWoZjxIk0UCp1GqN85O4KcZHXFA4eMpikO9FbInK1Jg6@lists.postgresql.org X-Gm-Message-State: AOJu0Yz8zROLTQyPwp0oOqZAG2l8azcJ01nC9yEYow176p0I6DfEwjri w71fXaqvRizcNICKj5NYnT/sy1oLc3Szoy8aZbwSum7jyNr4o0qsSRkRJoxNZq6VS1zxpSnAKAL HYCnCWs7cVP7YQ2uccXyiMwP7T3EXWYY= X-Gm-Gg: ASbGnctjlEA3SQ6AhqJyRzojXlVOPLIpWk294ppukMl9wUs+R8be0EyebDGgVeZYG+t IrtN86+ziyddLhwmR5SUYQ+Bk+BfYme9ZNCH5Yu4w+TqTX1YnoY+Ha2FFsS517lC37+vZimv3wo GTXwbu9Rz+LW35ijOSiLlhzARG1AbHu82Ae0W341EGad9xLY6mMnruj61sZzW6rg4/R+u8+kHbN Qb/q417g/vRLWQsy7/w9omt8F9iKnkyuU3VhdIjGs1psEBZzkujkhuH+HFlhDyCCZ44OEXB X-Google-Smtp-Source: AGHT+IFE/0NlnyAL1zLDi2gLllcQsJOJU2RrbK2+g/lPsjNUWUiOJsiB2lVxcump9qo6No4BQqIqTSo3wdbHCWGOZj8= X-Received: by 2002:a05:6402:1449:b0:643:4e9c:d164 with SMTP id 4fb4d7f45d1cf-645eb23f957mr3946725a12.2.1764107050499; Tue, 25 Nov 2025 13:44:10 -0800 (PST) MIME-Version: 1.0 References: <2wk7jo4m4qwh5sn33pfgerdjfujebbccsmmlownybddbh6nawl@mdyyqpqzxjek> <0AC177F5-5E26-45EE-B273-357C51212AC5@gmail.com> In-Reply-To: <0AC177F5-5E26-45EE-B273-357C51212AC5@gmail.com> From: Melanie Plageman Date: Tue, 25 Nov 2025 16:43:58 -0500 X-Gm-Features: AWmQ_bnpSjRxM-fnbUBdm8XLep4FKsxsFaYQqR9yJjxT8g8XKsi5pNVmsRILJOY Message-ID: Subject: Re: eliminate xl_heap_visible to reduce WAL (and eventually set VM on-access) To: Chao Li Cc: Kirill Reshke , Andres Freund , Robert Haas , Andrey Borodin , PostgreSQL Hackers , Heikki Linnakangas 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 Thanks for the review! On Thu, Nov 20, 2025 at 8:10=E2=80=AFPM Chao Li wr= ote: > > * new_relfrozen_xid and new_relmin_mxid must provided by the caller if = the > - * HEAP_PRUNE_FREEZE option is set. On entry, they contain the oldest X= ID and > - * multi-XID seen on the relation so far. They will be updated with old= est > - * values present on the page after pruning. After processing the whole > - * relation, VACUUM can use these values as the new relfrozenxid/relminm= xid > - * for the relation. > + * HEAP_PAGE_PRUNE_FREEZE option is set in params. On entry, they conta= in the > + * oldest XID and multi-XID seen on the relation so far. They will be u= pdated > + * with oldest values present on the page after pruning. After processi= ng the > + * whole relation, VACUUM can use these values as the new > + * relfrozenxid/relminmxid for the relation. > */ > void > -heap_page_prune_and_freeze(Relation relation, Buffer buffer, > - GlobalVisState *vistes= t, > - int options, > - struct VacuumCutoffs *= cutoffs, > +heap_page_prune_and_freeze(PruneFreezeParams *params, > PruneFreezeResult *pre= sult, > - PruneReason reason, > OffsetNumber *off_loc, > TransactionId *new_rel= frozen_xid, > MultiXactId *new_relmi= n_mxid) > { > ``` > > For this function interface change, I got a concern. The old function com= ment says "cutoffs contains the freeze cutoffs =E2=80=A6. Required if HEAP_= PRUNE_FREEZE option is set.=E2=80=9D, meaning that cutoffs is only useful a= nd must be set when HEAP_PRUNE_FREEZE is set. But the new comment seems to = have lost this indication. I did move that comment into the PruneFreezeParams struct definition. > And in the old function interface, cutoffs sat right next to options, rea= ders are easy to notice: > > * when options is 0, cutoffs is null > ``` > heap_page_prune_and_freeze(relation, buffer, vist= est, 0, > = NULL, &presult, PRUNE_ON_ACCESS, &dummy_off_loc, NULL, NULL); > ``` > > * when options has HEAP_PAGE_PRUNE_FREEZE, cutoffs is passed in > ``` > prune_options =3D HEAP_PAGE_PRUNE_FREEZE; > if (vacrel->nindexes =3D=3D 0) > prune_options |=3D HEAP_PAGE_PRUNE_MARK_UNUSED_NOW; > > heap_page_prune_and_freeze(rel, buf, vacrel->vistest, prune_optio= ns, > &vacrel->cutof= fs, &presult, PRUNE_VACUUM_SCAN, > &vacrel->offnu= m, > &vacrel->NewRe= lfrozenXid, &vacrel->NewRelminMxid); > ``` > > So, the change doesn=E2=80=99t break anything, but makes code a little bi= t harder to read. So, my suggestion is to add an assert in heap_page_prune_= and_freeze, something like: > > Assert(!(params->options & HEAP_PAGE_PRUNE_FREEZE) || params->cutoffs != =3D NULL); That's fair. I've gone ahead and pushed a commit with your suggested assert= . > 2 - pushed 0001 > ``` > + PruneFreezeParams params =3D {.relation =3D rel,.buffer =3D buf, > + .reason =3D PRUNE_VACUUM_SCAN,.options =3D HEAP_PAGE_PRUN= E_FREEZE, > + .cutoffs =3D &vacrel->cutoffs,.vistest =3D vacrel->vistes= t > + }; > ``` > > Using a designated initializer is not wrong, but makes future maintenance= harder, because when a new field is added, this initializer will leave the= new field uninitiated. From my impression, I don=E2=80=99t remember I ever= see a designated initializer in PG code. I only remember 3 ways I have see= n: > > * use an initialize function to set every fields individually > * palloc0 to set all 0, then set non-zero fields individually > * {0} to set all 0, then set non-zero fields individually Well, the main reason you don't see them much in the code is that a lot of the code is old and we didn't require a c99-compliant compiler until fairly recently (okay like 2018/2019) -- and thus couldn't use designated initializers. I agree that they are rare for structs (they are quite commonly used with arrays), but they are there -- for example these bufmgr init macros #define BMR_REL(p_rel) \ ((BufferManagerRelation){.rel =3D p_rel}) #define BMR_SMGR(p_smgr, p_relpersistence) \ ((BufferManagerRelation){.smgr =3D p_smgr, .relpersistence =3D p_relpersistence}) #define BMR_GET_SMGR(bmr) \ (RelationIsValid((bmr).rel) ? RelationGetSmgr((bmr).rel) : (bmr).smgr) I don't see how it would be harder to remember to initialize a field with a designated initializer vs if you have to just remember to add a line initializing that field in the code. And using a designated initializer ensures all unspecified fields will be zeroed out. In general, I have seen threads [1] encouraging the use of designated initializers, so I'm inclined to leave it as is since it is committed, and I haven't heard other pushback. > 3 - pushed 0002 > ``` > prstate->all_visible =3D false; > + prstate->all_frozen =3D false; > ``` > > Nit: Now setting the both fields to false repeat in 6 places. Maybe add a= static inline function, say PruneClearVisibilityFlags(), may improve maint= ainability. I see your point. However, I don't think it would necessarily be an improvement. This function already has a lot of helpers you have to jump to to understand what's going on. And in the place where they are cleared most often, heap_prune_record_unchanged_lp_normal(), we set other fields of the prstate directly, so it is nice visual symmetry in my opinion to set them inline. I did want to use chained assignment (all_visible =3D all_frozen =3D false), but I have had people complain about that in my code before more than once, so I refrained. > 4 - pushed 0003 > ``` > + * opporunistically freeze, to indicate if the VM bits can be set. They= are > ``` > > Typo: opporunistically, missed a =E2=80=9Ct=E2=80=9D. Fixed in same commit that added the assert. - Melanie [1] https://www.postgresql.org/message-id/flat/5B873BED.9080501%40anastigma= tix.net#4a067c1314783f0e171b4e1be76f7574