Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1nNdyK-0002rt-93 for pgsql-hackers@arkaria.postgresql.org; Fri, 25 Feb 2022 17:01:36 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.92) (envelope-from ) id 1nNdyI-0003D9-Ri for pgsql-hackers@arkaria.postgresql.org; Fri, 25 Feb 2022 17:01:34 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1nNdyI-0003D0-Ij for pgsql-hackers@lists.postgresql.org; Fri, 25 Feb 2022 17:01:34 +0000 Received: from out4-smtp.messagingengine.com ([66.111.4.28]) by makus.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1nNdyG-0004au-7N for pgsql-hackers@lists.postgresql.org; Fri, 25 Feb 2022 17:01:33 +0000 Received: from compute4.internal (compute4.nyi.internal [10.202.2.44]) by mailout.nyi.internal (Postfix) with ESMTP id 230C15C01EA; Fri, 25 Feb 2022 12:01:31 -0500 (EST) Received: from mailfrontend2 ([10.202.2.163]) by compute4.internal (MEProxy); Fri, 25 Feb 2022 12:01:31 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=anarazel.de; h= cc:cc:content-type:date:date:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:sender:subject :subject:to:to; s=fm3; bh=v/u/hVBEKtiYR+hvvUPujtSEj2sRoSu1tM9vIA GdnAg=; b=U/YllA4ZH/1LXZ69B2dhw4QTFKTs5gB2lKTAHbMYKKoxnoY6HfnTQM 34LvFh2yhx45aYBDm64cFWzCCg+KkOBrMoW4AIVOaupnj9olPXxxL1cBWcJaiVyG 0RZ/ziSl2A7LneOrwwjy6DbaCkS6Dr1IBKzok6kKs/BCI/WYD0ibIEWG5jzJ0qYP xmyCKjHVF4jhEL1Z+5lJlxbgPDpYwo7oc+mkfH8EBReKW8oLc8zyxr4JZk3SUJ3F KqEmuVNy8DyBIvWHRdjBLod4l5Go5OsphRJ6gX6bDMN9nJJe5aw5FVaNBdPGrdGr qecZmTNa1PkkNMRfgYuJGBQF3hm7tU0A== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:date:date:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:sender:subject:subject:to:to:x-me-proxy:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm2; bh=v/u/hVBEKtiYR+hvv UPujtSEj2sRoSu1tM9vIAGdnAg=; b=Y+l+DlFTE+Z9tMDnoLPGCNMopoPPrSsTz 0K1xTlB64ebJu8KzYnONqk8+nZsNP79watZwbuVYA/lFLx7N/0tBz7wx45S5alas ituv38HJnr0YBzufZUcJL8QudS+Ub8ywpXUeg6KkL9Ze5ZyuGW334Hd5IylHQBmE E8PtFNOfL/RKOdD7yz4datBL066GjmynNiVCSpI8TfpHPqYaifxqdSB+7IqGgOMX u6N3D0OE6ovPQzgPmB83/Qenc9Wg93S0FGFGDluFj6+VFnoA7oWMiVBwGYkW9DY3 IqoVt0liFc4WGqCwxUKP4KcdimFoYVljudGPxd6fq3umPwCHP08LA== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvvddrleeggdelhecutefuodetggdotefrodftvf curfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfghnecu uegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenuc fjughrpeffhffvuffkfhggtggujgesthdtredttddtvdenucfhrhhomheptehnughrvghs ucfhrhgvuhhnugcuoegrnhgurhgvshesrghnrghrrgiivghlrdguvgeqnecuggftrfgrth htvghrnhepudekhfekleeugeevteehleffffejgeelueduleeffeeutdelffeujeffhfeu ffdunecuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomheprg hnughrvghssegrnhgrrhgriigvlhdruggv X-ME-Proxy: Received: by mail.messagingengine.com (Postfix) with ESMTPA; Fri, 25 Feb 2022 12:01:28 -0500 (EST) Date: Fri, 25 Feb 2022 09:01:27 -0800 From: Andres Freund To: Yura Sokolov Cc: Kyotaro Horiguchi , michail.nikolaev@gmail.com, x4mmm@yandex-team.ru, pgsql-hackers@lists.postgresql.org Subject: Re: BufferAlloc: don't take two simultaneous locks Message-ID: <20220225170127.lxe66l2swx3empgu@alap3.anarazel.de> References: <3b108afd19fa52ed20c464a69f64d545e4a14772.camel@postgrespro.ru> <20220217.141647.512059035403445205.horikyota.ntt@gmail.com> <1a97e80353d6855e9217cd6e2052257190a98f2d.camel@postgrespro.ru> <20220225080455.3zzxwfpvbizzcsfo@alap3.anarazel.de> 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 2022-02-25 12:51:22 +0300, Yura Sokolov wrote: > > > + * The usage_count starts out at 1 so that the buffer can survive one > > > + * clock-sweep pass. > > > + * > > > + * We use direct atomic OR instead of Lock+Unlock since no other backend > > > + * could be interested in the buffer. But StrategyGetBuffer, > > > + * Flush*Buffers, Drop*Buffers are scanning all buffers and locks them to > > > + * compare tag, and UnlockBufHdr does raw write to state. So we have to > > > + * spin if we found buffer locked. > > > > So basically the first half of of the paragraph is wrong, because no, we > > can't? > > Logically, there are no backends that could be interesting in the buffer. > Physically they do LockBufHdr/UnlockBufHdr just to check they are not interesting. Yea, but that's still being interested in the buffer... > > > + * Note that we write tag unlocked. It is also safe since there is always > > > + * check for BM_VALID when tag is compared. > > > > > > > */ > > > buf->tag = newTag; > > > - buf_state &= ~(BM_VALID | BM_DIRTY | BM_JUST_DIRTIED | > > > - BM_CHECKPOINT_NEEDED | BM_IO_ERROR | BM_PERMANENT | > > > - BUF_USAGECOUNT_MASK); > > > if (relpersistence == RELPERSISTENCE_PERMANENT || forkNum == INIT_FORKNUM) > > > - buf_state |= BM_TAG_VALID | BM_PERMANENT | BUF_USAGECOUNT_ONE; > > > + new_bits = BM_TAG_VALID | BM_PERMANENT | BUF_USAGECOUNT_ONE; > > > else > > > - buf_state |= BM_TAG_VALID | BUF_USAGECOUNT_ONE; > > > - > > > - UnlockBufHdr(buf, buf_state); > > > + new_bits = BM_TAG_VALID | BUF_USAGECOUNT_ONE; > > > > > > - if (oldPartitionLock != NULL) > > > + buf_state = pg_atomic_fetch_or_u32(&buf->state, new_bits); > > > + while (unlikely(buf_state & BM_LOCKED)) > > > > I don't think it's safe to atomic in arbitrary bits. If somebody else has > > locked the buffer header in this moment, it'll lead to completely bogus > > results, because unlocking overwrites concurrently written contents (which > > there shouldn't be any, but here there are)... > > That is why there is safety loop in the case buf->state were locked just > after first optimistic atomic_fetch_or. 99.999% times this loop will not > have a job. But in case other backend did lock buf->state, loop waits > until it releases lock and retry atomic_fetch_or. > > And or'ing contents in also doesn't make sense because we it doesn't work to > > actually unset any contents? > > Sorry, I didn't understand sentence :(( You're OR'ing multiple bits into buf->state. LockBufHdr() only ORs in BM_LOCKED. ORing BM_LOCKED is fine: Either the buffer is not already locked, in which case it just sets the BM_LOCKED bit, acquiring the lock. Or it doesn't change anything, because BM_LOCKED already was set. But OR'ing in multiple bits is *not* fine, because it'll actually change the contents of ->state while the buffer header is locked. > > Why don't you just use LockBufHdr/UnlockBufHdr? > > This pair makes two atomic writes to memory. Two writes are heavier than > one write in this version (if optimistic case succeed). UnlockBufHdr doesn't use a locked atomic op. It uses a write barrier and an unlocked write. Greetings, Andres Freund