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 1nNVb8-0007ah-CS for pgsql-hackers@arkaria.postgresql.org; Fri, 25 Feb 2022 08:05:06 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.92) (envelope-from ) id 1nNVb7-0007P7-2c for pgsql-hackers@arkaria.postgresql.org; Fri, 25 Feb 2022 08:05:05 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1nNVb6-0007Oy-Pc for pgsql-hackers@lists.postgresql.org; Fri, 25 Feb 2022 08:05:04 +0000 Received: from wout4-smtp.messagingengine.com ([64.147.123.20]) by magus.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1nNVb3-0001uA-JL for pgsql-hackers@lists.postgresql.org; Fri, 25 Feb 2022 08:05:04 +0000 Received: from compute2.internal (compute2.nyi.internal [10.202.2.46]) by mailout.west.internal (Postfix) with ESMTP id 4F1F73201FD3; Fri, 25 Feb 2022 03:04:58 -0500 (EST) Received: from mailfrontend1 ([10.202.2.162]) by compute2.internal (MEProxy); Fri, 25 Feb 2022 03:04:58 -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=QWk9dGy9lQNWHzqQbzesD8/69XiQy2gNpgR+aN QEINk=; b=Il+8V0YgK7S3rpEx3VKhy01DU+T1X2/EyKCjJp/SPD5lyLMZLhha8U esorVhOHVJfPt4BkFlR7K2fBxg8WhcVqZk9fIRt07uxatyevMvLmAk0zMdN7vyfl LZpVvwGOPjz0JshJ0aPr/4sqzZ72QhLYr2mAg2lNRYL1ljG0Bwk7A1GCmDSnIlL6 QlvgGdMZhy5ehoCILrxZrh2Tu2MDTPHAcIpavIQPVxVQZ+k1JlvK16kBqlvsqKDw qL3ZeMq6K4eAYKT3ARc5XExU/jkbFu+ndUz9EZQl5gntdGGfzL+k5CjCZGPbnNKh 4ttE5Lq/VdK156vy6yZazplrY6Xr4Sbw== 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=QWk9dGy9lQNWHzqQb zesD8/69XiQy2gNpgR+aNQEINk=; b=b+EwwzH1t2YhOz4UQX64b4KEWZunR5IY1 drsnp6dkLTqDEG787IX8V1t+qh1+0hUHeyZn7k3IMhcPEWJr384XqUR+yJYposXi fxGiDWCnO6LR/Oqi/7VGzStqqmfg3894dwpro4y85QP+6zbGsTtAeTiRuXjnESJ6 /I3GONscNillGVRnIM7p+B4p/WHeqoGm8NbaL7EgOarcGJnGliZ0aOQhN4PxdgnN jxLH/4eHjoIV12Xo4e4hWI8l5XySNbSikXuwRQgt3ebV64K38rV81DNaXxKdu3E2 emk4/yuHNxu+BWjyOlls9rm/xPkaQHP84LT6zCfemVoWOXQm16+Nw== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvvddrleefgddutdejucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvffukfhfgggtuggjsehttdertddttddvnecuhfhrohhmpeetnhgurhgv shcuhfhrvghunhguuceorghnughrvghssegrnhgrrhgriigvlhdruggvqeenucggtffrrg htthgvrhhnpedukefhkeelueegveetheelffffjeegleeuudelfeefuedtleffueejfffh ueffudenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpe grnhgurhgvshesrghnrghrrgiivghlrdguvg X-ME-Proxy: Received: by mail.messagingengine.com (Postfix) with ESMTPA; Fri, 25 Feb 2022 03:04:56 -0500 (EST) Date: Fri, 25 Feb 2022 00:04:55 -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: <20220225080455.3zzxwfpvbizzcsfo@alap3.anarazel.de> References: <3b108afd19fa52ed20c464a69f64d545e4a14772.camel@postgrespro.ru> <20220217.141647.512059035403445205.horikyota.ntt@gmail.com> <1a97e80353d6855e9217cd6e2052257190a98f2d.camel@postgrespro.ru> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <1a97e80353d6855e9217cd6e2052257190a98f2d.camel@postgrespro.ru> List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk Hi, On 2022-02-21 11:06:49 +0300, Yura Sokolov wrote: > From 04b07d0627ec65ba3327dc8338d59dbd15c405d8 Mon Sep 17 00:00:00 2001 > From: Yura Sokolov > Date: Mon, 21 Feb 2022 08:49:03 +0300 > Subject: [PATCH v3] [PGPRO-5616] bufmgr: do not acquire two partition locks. > > Acquiring two partition locks leads to complex dependency chain that hurts > at high concurrency level. > > There is no need to hold both lock simultaneously. Buffer is pinned so > other processes could not select it for eviction. If tag is cleared and > buffer removed from old partition other processes will not find it. > Therefore it is safe to release old partition lock before acquiring > new partition lock. Yes, the current design is pretty nonsensical. It leads to really absurd stuff like holding the relation extension lock while we write out old buffer contents etc. > + * We have pinned buffer and we are single pinner at the moment so there > + * is no other pinners. Seems redundant. > We hold buffer header lock and exclusive partition > + * lock if tag is valid. Given these statements it is safe to clear tag > + * since no other process can inspect it to the moment. > + */ Could we share code with InvalidateBuffer here? It's not quite the same code, but nearly the same. > + * 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? > + * 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)... And or'ing contents in also doesn't make sense because we it doesn't work to actually unset any contents? Why don't you just use LockBufHdr/UnlockBufHdr? Greetings, Andres Freund