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.94.2) (envelope-from ) id 1r5Qlh-00DSMu-1i for pgsql-hackers@arkaria.postgresql.org; Tue, 21 Nov 2023 13:26:21 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.94.2) (envelope-from ) id 1r5Qlf-00GmUW-JB for pgsql-hackers@arkaria.postgresql.org; Tue, 21 Nov 2023 13:26:19 +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.94.2) (envelope-from ) id 1r5Qlf-00GmUO-7x for pgsql-hackers@lists.postgresql.org; Tue, 21 Nov 2023 13:26:19 +0000 Received: from mail-wr1-x42e.google.com ([2a00:1450:4864:20::42e]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.94.2) (envelope-from ) id 1r5QlX-007bht-Ip for pgsql-hackers@lists.postgresql.org; Tue, 21 Nov 2023 13:26:18 +0000 Received: by mail-wr1-x42e.google.com with SMTP id ffacd0b85a97d-33139ecdca7so3372713f8f.0 for ; Tue, 21 Nov 2023 05:26:10 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=enterprisedb.com; s=google; t=1700573169; x=1701177969; darn=lists.postgresql.org; h=content-transfer-encoding:in-reply-to:from:references:cc:to :content-language:subject:user-agent:mime-version:date:message-id :from:to:cc:subject:date:message-id:reply-to; bh=Io4OvUtSI15cHDI6ydg5TV1j52LBqLSblIItXGm8fhM=; b=jikJCNpNEe6Lesm2RKXfKaRJd/jC1XYmaVkoaq4mRWqGb5lDQ06fuF6D/9bh9dkRwe JHVyOciEGpqvD/hdV9OejB3lkOW1N14XGXooeLUeY5LivBcCiWmBV06T20h6pMa6KPqc 6GnbeaxOXC/w07JrMbTSzkh8TFhUqleBV7+zCGfFGUaBSEDOy8F7HXX6DLCSjhhryefb xFPA394pzZEqrDikom1TvyNZ/yAqxnPMOo3WYL69+emBnjWiw4PSjfJFzqp48ydSVB9i GJHTTTLOmrwT0/UfmCpYubazL6qjzK2zFBS53cc8UMTn/1IGu/21n+sCknixZq5ele53 Khqg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1700573169; x=1701177969; h=content-transfer-encoding:in-reply-to:from:references:cc:to :content-language:subject:user-agent:mime-version:date:message-id :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=Io4OvUtSI15cHDI6ydg5TV1j52LBqLSblIItXGm8fhM=; b=IafcppZ3SKavXIqF2oEGclZIWv1i1Tn8VD8YKxoH7Ou1CkE+Up06HB2JcRPm56tjQS vl+a6e+yUbecR9oUkitSp4tMGz5xXV+oGZoFQUr8ruExQ3dHJRIrObew22/r/IhKk1/g 3rKxwerp9bgoz/tgf+Gfe1Wl9hwEnHb5XGbRr9QTyF3rySmaFTLI8V6Ig1c9sc5yBwvu 77DyncWrorDabkwnEj/tjTHnupbr9jvvh35bY7fr6uUiEqGWkU+sfFZ4+0DHv52EPDa4 ipWBaqyOTK8cbXbHUdEScGiTlhLprXMqwgPtaG0klGUnrkLR6CJnrxVhlnAWE/g4nJ46 QJTw== X-Gm-Message-State: AOJu0YxihiMVxiezH797Ry6mIcQ6L4dE7+E1DVtgxT/Q2oxsT6kkhGZq Cgooa2MVvwbnYQv94avyP/sJNw== X-Google-Smtp-Source: AGHT+IER6vGF7KOF3oKk5FeqJKuOnMV5x/vxk1m9SnXUZbtPnYj76nzawAU7d+4DYmEXBLhLhq4s8A== X-Received: by 2002:a5d:64cd:0:b0:32d:8830:ee2 with SMTP id f13-20020a5d64cd000000b0032d88300ee2mr9831874wri.43.1700573169368; Tue, 21 Nov 2023 05:26:09 -0800 (PST) Received: from [10.137.0.17] (srv1.mobissw.com. [89.235.0.226]) by smtp.gmail.com with ESMTPSA id c11-20020adffb0b000000b0032ddf2804ccsm14396678wrr.83.2023.11.21.05.26.08 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Tue, 21 Nov 2023 05:26:09 -0800 (PST) Message-ID: <8948e4a2-fec7-8a61-9ace-2537cee3ef6f@enterprisedb.com> Date: Tue, 21 Nov 2023 14:26:08 +0100 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Thunderbird/102.15.1 Subject: Re: undetected deadlock in ALTER SUBSCRIPTION ... REFRESH PUBLICATION Content-Language: en-US To: Amit Kapila Cc: PostgreSQL Hackers References: From: Tomas Vondra In-Reply-To: Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk On 11/21/23 14:16, Amit Kapila wrote: > On Tue, Nov 21, 2023 at 5:17 PM Tomas Vondra > wrote: >> >> I decided to do some stress-testing of the built-in logical replication, >> as part of the sequence decoding work. And I soon ran into an undetected >> deadlock related to ALTER SUBSCRIPTION ... REFRESH PUBLICATION :-( >> >> The attached bash scripts triggers that in a couple seconds for me. The >> script looks complicated, but most of the code is waiting for sync to >> complete, catchup, and that sort of thing. >> >> What the script does is pretty simple: >> >> 1) initialize two clusters, set them as publisher/subscriber pair >> >> 2) create some number of tables, add them to publication and wait for >> the sync to complete >> >> 3) start two pgbench runs in the background, modifying the publication >> (one removes+adds all tables in a single transaction, one does that >> with transaction per table) >> >> 4) run refresh.sh which does ALTER PUBLICATION ... REFRESH PUBLICATION >> in a loop (now that I think about it, could be another pgbench >> script, but well ...) >> >> 5) some consistency checks, but the lockup happens earlier so this does >> not really matter >> >> After a small number of refresh cycles (for me it's usually a couple >> dozen), we end up with a couple stuck locks (I shortened the backend >> type string a bit, for formatting reasons): >> >> test=# select a.pid, classid, objid, backend_type, query >> from pg_locks l join pg_stat_activity a on (a.pid = l.pid) >> where not granted; >> >> pid | classid | objid | backend_type | query >> ---------+---------+-------+------------------+---------------------- >> 2691941 | 6100 | 16785 | client backend | ALTER SUBSCRIPTION s >> REFRESH PUBLICATION >> 2691837 | 6100 | 16785 | tablesync worker | >> 2691936 | 6100 | 16785 | tablesync worker | >> (3 rows) >> >> All these backends wait for 6100/16785, which is the subscription row in >> pg_subscription. The tablesync workers are requesting AccessShareLock, >> the client backend however asks for AccessExclusiveLock. >> >> The entry is currently locked by: >> >> test=# select a.pid, mode, backend_type from pg_locks l >> join pg_stat_activity a on (a.pid = l.pid) >> where classid=6100 and objid=16785 and granted; >> >> pid | mode | backend_type >> ---------+-----------------+---------------------------------- >> 2690477 | AccessShareLock | logical replication apply worker >> (1 row) >> >> But the apply worker is not waiting for any locks, so what's going on? >> >> Well, the problem is the apply worker is waiting for notification from >> the tablesync workers the relation is synced, which happens through >> updating the pg_subscription_rel row. And that wait happens in >> wait_for_relation_state_change, which simply checks the row in a loop, >> with a sleep by WaitLatch(). >> >> Unfortunately, the tablesync workers can't update the row because the >> client backend executing ALTER SUBSCRIPTION ... REFRESH PUBLICATION >> sneaked in, and waits for an AccessExclusiveLock. So the tablesync >> workers are stuck in the queue and can't proceed. >> >> The client backend can't proceed, because it's waiting for a lock held >> by the apply worker. >> > > It seems there is some inconsistency in what you have written for > client backends/tablesync worker vs. apply worker. The above text > seems to be saying that the client backend and table sync worker are > waiting on a "subscription row in pg_subscription" and the apply > worker is operating on "pg_subscription_rel". So, if that is true then > they shouldn't get stuck. > > I think here client backend and tablesync worker seems to be blocked > for a lock on pg_subscription_rel. > Not really, they are all locking the subscription. All the locks are on classid=6100, which is pg_subscription: test=# select 6100::regclass; regclass ----------------- pg_subscription (1 row) The thing is, the tablesync workers call UpdateSubscriptionRelState, which locks the pg_subscription catalog at the very beginning: LockSharedObject(SubscriptionRelationId, ...); So that's the issue. I haven't explored why it's done this way, and there's no comment explaining locking the subscriptions is needed ... >> The tablesync workers can't proceed because their lock request is stuck >> behind the AccessExclusiveLock request. >> >> And the apply worker can't proceed, because it's waiting for status >> update from the tablesync workers. >> > > This part is not clear to me because > wait_for_relation_state_change()->GetSubscriptionRelState() seems to > be releasing the lock while closing the relation. Am, I missing > something? > I think you're missing the fact that GetSubscriptionRelState() acquires and releases the lock on pg_subscription_rel, but that's not the lock causing the issue. The problem is the lock on the pg_subscription row. regards -- Tomas Vondra EnterpriseDB: http://www.enterprisedb.com The Enterprise PostgreSQL Company