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 1wiCXf-00046h-2a for pgsql-hackers@arkaria.postgresql.org; Fri, 10 Jul 2026 14:49:28 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1wiCXe-000lzP-0o for pgsql-hackers@arkaria.postgresql.org; Fri, 10 Jul 2026 14:49:26 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1wiCXd-000lzH-1d for pgsql-hackers@lists.postgresql.org; Fri, 10 Jul 2026 14:49:26 +0000 Received: from fhigh-b3-smtp.messagingengine.com ([202.12.124.154]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.98.2) (envelope-from ) id 1wiCXa-00000000fPt-3saJ for pgsql-hackers@lists.postgresql.org; Fri, 10 Jul 2026 14:49:25 +0000 Received: from phl-compute-04.internal (phl-compute-04.internal [10.202.2.44]) by mailfhigh.stl.internal (Postfix) with ESMTP id A2E107A0101; Fri, 10 Jul 2026 10:49:20 -0400 (EDT) Received: from phl-frontend-03 ([10.202.2.162]) by phl-compute-04.internal (MEProxy); Fri, 10 Jul 2026 10:49:20 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=anarazel.de; h= cc:cc:content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:subject :subject:to:to; s=fm2; t=1783694960; x=1783781360; bh=NV4ablmhya OJaDrFHdqya5oNO/cK1vNTxTDGPd+xKcY=; b=WBab7PFvOwpdKqsuQDMZQuW4f3 KnOWphcXtk8ldljkFkCzW1tgWc9Y3d//YP7gkYQUyuTstKPRdEHfpfojVajNTSno b3W+cUP3jXEwXF6ekgp5FwNJbgVMKo8+OGOdl/+pED9EVihJ/EnvpROzmQPlSWnf rHGaOI509/FHYc420gxGlXj2lr1jrslGzByJMoR4jKYHhVunPm+2RaXLNCoKdRH2 rX9Gs1335GG9+4Jy2JYD/7GblQMBw0S88p/0lAf8flvb52mrfG6DwzagIJZgbxXN vUEYcuekCATmqr5GUODjqHnS/PPTDKgrd0KKosobfR5Ewyl5hDdwP+rbMDCg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm2; t= 1783694960; x=1783781360; bh=NV4ablmhyaOJaDrFHdqya5oNO/cK1vNTxTD GPd+xKcY=; b=kn68X8msLsDquT7VOBx625ag+BRIR0WeUntLTrzv3sePdKgy2M1 dEFC/8xQPgS/Org9C/5iuIpDT7U3U78yU6zIPPpMzkXqrT4udSBF/q7OJb3Kwj2K BhEtk1hLUmkH/N1ht7XuBH+ezCZMn55o8ItCThQv230ZIeYXT48EY5v+QgTlzjlk aXI1XXLiYVA/HKmkeyrXdO/z+XWuJyBkrcpyYFg9XzEym5MB/5Zk9RrD0zOZWHZq qsOkdJhQZCQzqbjMAFM35s1rmsEsHtkLemV6VilbI510MScVJn+pOzPox/6Vix1B NLry54LW30KwP4HF6Ie9+rTZgz93jMOeNLw== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: dmFkZTFkoFjsWgCNjJGIoFsSXeU7Gj9SNYOG8tnDu6vvLlOgWL2PKwkmqxFZnbeghSxXQb OU/z0luWz/SEoZ6RUoXftQoS93bY5tE+waoY1tM2MPI8WiRR+CNbggBvFKOdzogEbP7KDc nJ/Sqsbvp0wBKJomLeQmkJdrNS7TzU5Ei8RwrSImF9mNGU7Bi1ziXDUEvdNzCcWf11JiRo 8dWL2GLFnBslwKoVVqrMdxPvnXMnjDmIePr/tPF/L2hmPLYvYQn+ugRLsbuGU9xWO1q47o wDSxZW4t5yYMTCD77cb3y9y6Uu55UAOy70CGoyFpR48mnVMtIcCOlabqItlD8LWX9al/fw 94EVDkycc8V7Vsd5VCZjr/OBBfFWw/V3ZYYtbIp38x3LzRNNdo7F132jdrQ5+SursioToT c+Dt9X+LPvzrZHp0uj1pKy/ljrqH9v0dYJYwHvtgkZftMp0GOS3WeqpMxdBScRLxLEvgXd NcPEzCnvTh5DKFj9UkH9gCVjbN+fPRrMS10vVgbdFw+693/D/Ze0q4eK79HV7oFrZrG02I ejbtx0XzXechHdaTVZUoTikAAQdPZYklu/r20/3h3DkPlb3MAQ96gKkcbpZEwOR3povC6G JvqeMpBOSjxYf9TD6gxH0ex9utPAbVGYFaddu2HgU3HWDkqw0QdcAsf3b4Jg X-ME-Proxy: Feedback-ID: id4a34324:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Fri, 10 Jul 2026 10:49:20 -0400 (EDT) Date: Fri, 10 Jul 2026 10:49:19 -0400 From: Andres Freund To: Melanie Plageman Cc: PostgreSQL Hackers Subject: Re: Missing FSM Update when Updating VM On-access Message-ID: References: MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk Hi, On 2026-06-29 18:32:47 -0400, Melanie Plageman wrote: > I tried to think of some heuristics so that we could limit when we did > the FSM pinning and locking, but none seemed very good. We could check > if the new amount of free space is bigger than an FSM category step > (32), but that doesn't help us if we are correcting an FSM > overestimation. This could happen because inserts don't update the FSM > until the inserting tuple doesn't fit on the target page. One potential heuristic would be to skip trying to update the FSM if the page is considered full and we didn't remove any tuples (i.e. just marked it as all-visible). Skipping the FSM update in that case would, at worst, lead to unnecessarily visiting the page during a future insert (finding it to be full when doing so). We could additionally make it depend on whether PD_PAGE_FULL is set (in which case we presumably already updated the FSM). The case where that would potentially help is when doing the first scan through a freshly bulk loaded table. However, compared to the other costs in that case, I have a hard time believing the FSM access is that bad. And given the point in the release cycle, I think going for simpler is the way to go. > I also thought of caching the pinned FSM page in the scan descriptor > like we do with the VM page. This doesn't work as nicely because each > FSM page covers fewer heap pages. I don't think that'd be an issue, an FSM page still covers thousands of heap pages. I'd guess we'd need maybe a dozen pages or so to make the pin cost basically invisible. > Also, the pinning and unpinning all happens inside of the FSM API functions. However that definitely is an issue. I think it'd be good to renovate the FSM functions, which also would allow us to do things like pinning the FSM page before a critical section and then updating it as part of the CS, like we already do for the VM. The biggest benefit we could get is to avoid a lot of repeated work during relation extension. We do separate RecordPageWithFreeSpace() calls for each newly created page, and then a FreeSpaceMapVacuumRange() for all of them. That's a lot of repeated pinning. And I've seen those accesses be rather contended in concurrent COPY, so making them more efficient would be rather nice. But that's all clearly >19 material. > Therefore, I think the best option is the simplest -- if we set the > page all-visible, also see if we should update the FSM. Agreed. > @@ -376,16 +380,32 @@ heap_page_prune_opt(Relation relation, Buffer buffer, Buffer *vmbuffer, > if (presult.ndeleted > presult.nnewlpdead) > pgstat_update_heap_dead_tuples(relation, > presult.ndeleted - presult.nnewlpdead); > + > + /* > + * If this prune newly set the page all-visible, VACUUM may later > + * skip the page and thus not update its free space map (FSM) > + * entry. Keep the FSM from going stale by recording it now. We do > + * not want to update the freespace map otherwise (to reserve > + * freespace on this page for future updates). > + */ > + if (presult.newly_all_visible) > + { > + record_free_space = true; > + freespace = PageGetHeapFreeSpace(page); > + } > } > > /* And release buffer lock */ > LockBuffer(buffer, BUFFER_LOCK_UNLOCK); > > /* > - * We avoid reuse of any free space created on the page by unrelated > - * UPDATEs/INSERTs by opting to not update the FSM at this point. The > - * free space should be reused by UPDATEs to *this* page. Does the logic in this removed comment actually make sense to anyone? Because it sure doesn't to me. I don't even know what the hell "unrelated" UPDATEs/INSERTs means here. We don't have the slightest idea what's related and unrelated, assuming that means it's for different tuples than what this backend is reading the page for. Sure, in-page updates are good (hot, general efficiency). But we do update the FSM in other places without this consideration, so using that argument to skip an FSM update here seems ... bogus. I could see an argument for not inserting almost full pages into the FSM, but if we went for that, it'd not be just this place we'd want to do so. Greetings, Andres Freund