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 1wCpmU-002Lob-0n for pgsql-hackers@arkaria.postgresql.org; Wed, 15 Apr 2026 02:15:06 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1wCpmS-00E2xI-1K for pgsql-hackers@arkaria.postgresql.org; Wed, 15 Apr 2026 02:15:05 +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 1wCpmR-00E2x8-3C for pgsql-hackers@lists.postgresql.org; Wed, 15 Apr 2026 02:15:05 +0000 Received: from mail-pl1-x62a.google.com ([2607:f8b0:4864:20::62a]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.98.2) (envelope-from ) id 1wCpmQ-000000014Gk-2yOf for pgsql-hackers@postgresql.org; Wed, 15 Apr 2026 02:15:04 +0000 Received: by mail-pl1-x62a.google.com with SMTP id d9443c01a7336-2b2589c26e3so56150065ad.1 for ; Tue, 14 Apr 2026 19:15:02 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1776219302; cv=none; d=google.com; s=arc-20240605; b=EYBjViQP7q6LDHZgpHo+OrNTN6tbxBUf8BhHybn1kkwa5hbdLO70ut8lgmW/aSGlPd QRbFjyPyok1IxKW55dwihLXX/fsM0fXPxExYNgV2s5P/Id3T204Pj6juOZluMW92Fa0N cCRobxoxNzHn61cyorEsN0nb1bygzBWb3M3GHFxwwviWWUVKUo/WMHE0l5GxwMZxiRuB sG5xzlH4Wei+7rbm9tQ/FcGwY8gAd+XaK7murpINdBlgopmzPXRYbYH+RAGXEBaFmLLp wUd8Zx1m1EsWRrw9KOstYsvLxD3bocwX7N3emNXMJNtnoCjflrtkcf3e7pF3OR1L248W 4HUg== 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=bU3OaaU0CbdpqBfYW77VY11fPKW5Itx8ndhgm+bULHo=; fh=SN0t278eZZLlGEeX/TDeaxL0uj/BzGb7PUpx53x4ydg=; b=Yx1zb/J6YqBsz6a0VhnG3xOVT2r1uTGMD5CsAKCayQYpin1Xh0s1D81Mq6s/DijSKW 0gCZHZehizzieJXgT4FkPiBqW9Rt0NxfaErlAvp1Ww35mIAPd5EKuPUqbuXgfMOq+nPD 6NuB3NxInJszE1fM1G1N3wkB3S8EKmMysw5PEJqkEL1xskVA63BPngGegRagVddBNMBu dnzEsu3d/uJK6hAvZx5N3J+3UE2etNf9c3gX54umXvB+NZm1N9xViTN9OGzyoP28kJij YjO5c0aBIEIle3F0XS+qcWgxd+HLDuhGQMIqhU3DeEO+5sMmhSpw8KRSPw0gZTAZbCot +FeQ==; 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=1776219302; x=1776824102; 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=bU3OaaU0CbdpqBfYW77VY11fPKW5Itx8ndhgm+bULHo=; b=bKn7r9mOSoV9/oXqn9eMCmb4y9brtMh29NEXJSFdQeaWfhD3XVKADjmZv8mKhj5iGH fRPa2gTc5uUyiwjnOnVmH0npLaH24Bl+AeK1PJJTOlQz4xbEGdy8X2cWnuBsFR+iUq2t nQYpGz8cSHkCBFGXfoPGsnvCIz8USKDupSORfhp/p1ovhPHe9i2C25NrfnMEp7Do05Ni 1NiNwOwTDoWaloX5lwgUZU+6NUc24ar8lzol6cvXQdK5RvHBx5aWd653oldvUZPTHbjV CuAeI+JE4MNvA6jTSwY2hyfkWXrsk90lZ0SUCqleWs+0NkvlaP58bNcsOkASjKSGK0nK CdLQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1776219302; x=1776824102; 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=bU3OaaU0CbdpqBfYW77VY11fPKW5Itx8ndhgm+bULHo=; b=FmTp4F16Er0V9tf5ETZki+pOtAiwuU7rQTJyVq6GLlygGGLkXOkmGBbEdRc6oCbmUv xoZkXM57hfOghiBkoXtdd7j/DaFh+owJ/ItzEyOf0FyDxxZeeazgABiLWVHH63rkc3Gi 76OOKHcHg2ih/imMOXmB0vpsKeQNUUX6iM4pMHhYJ5rjaElbkImQVZCANTDjR8d3uZ6r 5ojyOSayTadAGHSbH67BPS/ZyXfvyPAQD+qdGpl/VZsnkxid+Ua48NCHrB6Y9uF0p/WH +SAZ6D7tzH377wynHIc8jWmZ7GJrXTBJiTbKPuKMJrdVnALwpEehxnZSnF0i6c078qCd Q/dQ== X-Gm-Message-State: AOJu0YxMehKAPmTfvR4B4HbUVWk5cCZ/YeY1ffkuMLpXeNrgvuMWwbOt +qz97FwmhlofA+s9eWYYuA+mFsrLOemUK6r4yNOuagQ3i9jdsDZV5oKp+ftEbbwPiodCUEtC0N0 vy9Lya0ZNeN5k5PwX+3Hl7KvbRINvBo0= X-Gm-Gg: AeBDietsk5xKtBbszfsjaI8MyE/r8P7YcTltsdgXkjyeFIWoE3uRAj5CrXTJfZAwXzQ QbRbso0myrFmI/OdXCR5LlDykf2J4/V+97At+zb9DhCel0C/f+O6BgFKpwHg8LwD/PkhORxJwhu FIcHLVjEzp5ta7MM/VzU7iyGmCzT5ba5AUmeS44ZfkJdrDycUIhBIAzidB4Myo4/+wUV//7mtQr 8qddOeJKWjKLJfScXcnXkJV4trxGQJBGAQwmfmXtFHZ68fLIbYm/3yik+TuJU2vqeD7+S+sQQ/d Qq1I5D5NVgm+EXqLLZ2RuEyH7w5ohewYl+aSEOW1YFiSNa38FNTCEPu0YcbKe8pVl+5QErZlYlQ = X-Received: by 2002:a17:902:b193:b0:2b0:bebb:1081 with SMTP id d9443c01a7336-2b2d5a5de38mr158871335ad.28.1776219302086; Tue, 14 Apr 2026 19:15:02 -0700 (PDT) MIME-Version: 1.0 References: In-Reply-To: From: Amit Langote Date: Wed, 15 Apr 2026 11:14:45 +0900 X-Gm-Features: AQROBzBiX2515kjJ7esncxPO8Zld3N17dSvujNMYCwvttq_Vg7EmFV8dRVxEExk Message-ID: Subject: Re: GetCachedPlan() refactor: move execution lock acquisition out To: Kirill Reshke Cc: 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 Hi, On Wed, Apr 15, 2026 at 1:08=E2=80=AFAM Kirill Reshke wrote: > On Tue, 14 Apr 2026 at 13:20, Amit Langote wrot= e: > > Over in the "generic plans and initial pruning" thread [1], I came to > > think that the cleanest way to address the architectural issue behind > > that thread is to make GetCachedPlan() do less execution-related work. > > Specifically, it should stop acquiring execution locks itself, and > > leave that decision to callers. > > > > GetCachedPlan() has long combined plan acquisition with execution > > setup, and that coupling makes it harder to improve either side > > cleanly. Tom pointed in this direction back in 2023 [2]: > > > > "...the whole problem arises because the system is wrongly factored. > > We should get rid of AcquireExecutorLocks altogether, allowing the > > plancache to hand back a generic plan that it's not certain of the > > validity of, and instead integrate the responsibility for acquiring > > locks into executor startup." > > > > This patch takes the first half of that suggestion by moving execution > > locking out of the plancache and into its callers. > > > > The attached patch does that, with no intended behavioral change: > > > > * Remove AcquireExecutorLocks() from CheckCachedPlan(), so > > GetCachedPlan() returns a plan without holding execution locks. > > > > * Add a new internal helper in plancache.c, LockCachedPlan(), which > > acquires execution locks, rechecks validity, and returns false if the > > plan was invalidated, so the caller can retry. > > > > * Add GetCachedPlanLocked() as a convenience wrapper that fetches a > > plan, calls LockCachedPlan(), and retries on invalidation. This > > becomes the normal entry point for callers that want a plan ready for > > execution. > > > > * Convert existing GetCachedPlan() callers to use GetCachedPlanLocked()= . > > > > The second half of Tom's suggestion, moving that responsibility into > > executor startup, is trickier. ExecutorStart() is a stable API with > > extension hooks, so changing its contract has a fairly high bar. I > > tried that route once already [3]. > > > > A working variant that adds an ExecutorPrep() entry point, with a > > wrapper implementing pruning-aware locking on top, was discussed in > > the original thread [1]. But rather than propose that whole stack at > > once, I think it is better to do this in phases: first decouple plan > > acquisition from execution locking, then revisit the ExecutorPrep() > > piece separately if this goes in. > > > > The eventual goal is still pruning-aware locking. I'm posting this > > piece separately because the original thread has become fairly long, > > and this part seems easier to review on its own. > > Hi! I have slightly checked v1. Can't tell if refactoring does make > cached plan maintenance more straightforward because of lack of > experience in this area, but here's my 2c Thanks for taking a look. Could you say a bit more about what aspect of cached plan maintenance you have in mind? My main motivation here is to separate plan acquisition from execution-time locking, so that locking policy no longer has to live inside GetCachedPlan(). > > + > > + for (;;) > > + { > > + cplan =3D GetCachedPlan(plansource, boundParams, owner, queryEnv); > > + if (LockCachedPlan(cplan)) > > + break; > > + > > + ReleaseCachedPlan(cplan, owner); > > + } > > Should we use CFI here? Good point. On a closer look, I think the retry loop can go away entirely. If LockCachedPlan() fails, releasing the plan and calling GetCachedPlan() again is enough, because that will rebuild the plan and the needed locks will already be held by the planner. I'll simplify that in the next version. > > +static bool > > +LockCachedPlan(CachedPlan *cplan) > > +{ > > + AcquireExecutorLocks(cplan->stmt_list, true); > > + if (!cplan->is_valid) > > + { > > + AcquireExecutorLocks(cplan->stmt_list, false); > > + return false; > > + } > > + return true; > > +} > > simply `return cplan->is_valid ` would be more Postgres-y here, isnt it? Agreed, will fix too. I'll hold off on posting a v2 for now. --=20 Thanks, Amit Langote