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 1r4IbN-0088ss-Ia for pgsql-hackers@arkaria.postgresql.org; Sat, 18 Nov 2023 10:31:01 +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 1r4IbM-000LKk-2u for pgsql-hackers@arkaria.postgresql.org; Sat, 18 Nov 2023 10:31:00 +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 1r4IbL-000LKb-Oo for pgsql-hackers@lists.postgresql.org; Sat, 18 Nov 2023 10:30:59 +0000 Received: from mail-lj1-x22c.google.com ([2a00:1450:4864:20::22c]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.94.2) (envelope-from ) id 1r4IbJ-0072w0-9f for pgsql-hackers@lists.postgresql.org; Sat, 18 Nov 2023 10:30:58 +0000 Received: by mail-lj1-x22c.google.com with SMTP id 38308e7fff4ca-2c83d37a492so35111001fa.3 for ; Sat, 18 Nov 2023 02:30:56 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=enterprisedb.com; s=google; t=1700303455; x=1700908255; darn=lists.postgresql.org; h=content-transfer-encoding:in-reply-to:from:content-language :references:cc:to:subject:user-agent:mime-version:date:message-id :from:to:cc:subject:date:message-id:reply-to; bh=m4xCLZhzxSz/HCNkSgGEX9t0l7Jq/ecP7nkR3qV17FQ=; b=lt30oC2+YIHc3GdWb1jKRtq2r8KEgi1XR2pUGDGq32v4fDDrmjOcBPokjwKKKZzCNL VhDseld7U1OQ4q3CShFVhg1wjubLTTJjpvHU6PzdpKyjybDDVe7LlaRbIM2K/HL1yt6K Z/wy12v2kxR5M89MmFqKXtLE9E+UHiov/k0K6d6WR6wCCMHiIOgDFHdpOUm0Psmt4Tjr 6Hj8txREh06d0TyTOu7R2VJXtUhCc1mOIQ/AexOnuxomSx0bm4sG7FOC4AbHl3H1uNu8 OOpWdDsbFE0xVWyND/R8kz5n7zfewS2k8iGMTa0vyzs82a1wERa8BwESdYHjX9CWxKoQ PcbA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1700303456; x=1700908256; h=content-transfer-encoding:in-reply-to:from:content-language :references:cc:to:subject:user-agent:mime-version:date:message-id :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=m4xCLZhzxSz/HCNkSgGEX9t0l7Jq/ecP7nkR3qV17FQ=; b=jWQzukndAPkULPeZX8XBJrmI2NYKgqiMP6DyG/PsaJiTeVc8N3GXZKB/FrkLl0xWgI ypgwcSaf8X3farGacVmAl5otC6ID6Ru31g7/bYA+kfdmUjI4Mh+4AmBQxkpDYl4AxzAu 6FzDr8PZW5wFJslr/DGq+evj3FDdfTSsqwdBzPwKER76vNgHqUZeN9mCLxXslnVzbXIp 8Eg4aoybzAUZOe0yPvymIWquiO3tPS0Uy7IkISqN5UNNpRAz0EFp9Gzth4JhJy0+VnHy TcXjcUtBBg9/1ncBWqX4cKLr64SziMVp0W5v4oUHoHxkyncI6ZIj9J+KBkHaOcDCamBk +HgA== X-Gm-Message-State: AOJu0YxVa5YI4cZZHTkAZUHhYn7wHjCnUwuxFjezWw2tNru3SSRdyvYh VActjZNjNCzjWUregnINEebHbmG6qGg85zhPKro= X-Google-Smtp-Source: AGHT+IGoxXfFTYq4VN2qh6Yb1M4rbE9GmWK7CcOPTCsinNMpbrUhNShJhzABnTCszqp3DvuC2KWlIA== X-Received: by 2002:a2e:9096:0:b0:2b9:ea17:558b with SMTP id l22-20020a2e9096000000b002b9ea17558bmr1438968ljg.16.1700303455507; Sat, 18 Nov 2023 02:30:55 -0800 (PST) Received: from [10.137.0.17] (ip-86-49-250-157.bb.vodafone.cz. [86.49.250.157]) by smtp.gmail.com with ESMTPSA id k39-20020a05600c082700b004083729fc14sm10139760wmp.20.2023.11.18.02.30.55 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Sat, 18 Nov 2023 02:30:55 -0800 (PST) Message-ID: Date: Sat, 18 Nov 2023 11:30:53 +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: long-standing data loss bug in initial sync of logical replication To: Andres Freund Cc: PostgreSQL Hackers References: <20231118015443.sfxfbr4eqolxbmjc@awork3.anarazel.de> Content-Language: en-US From: Tomas Vondra In-Reply-To: <20231118015443.sfxfbr4eqolxbmjc@awork3.anarazel.de> Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk On 11/18/23 02:54, Andres Freund wrote: > Hi, > > On 2023-11-17 15:36:25 +0100, Tomas Vondra wrote: >> It seems there's a long-standing data loss issue related to the initial >> sync of tables in the built-in logical replication (publications etc.). > > :( > Yeah :-( > >> Overall, this looks, walks and quacks like a cache invalidation issue, >> likely a missing invalidation somewhere in the ALTER PUBLICATION code. > > It could also be be that pgoutput doesn't have sufficient invalidation > handling. > I'm not sure about the details, but it can't be just about pgoutput failing to react to some syscache invalidation. As described, just resetting the RelationSyncEntry doesn't fix the issue - it's the syscache that's not invalidated, IMO. But maybe that's what you mean. > > One thing that looks bogus on the DDL side is how the invalidation handling > interacts with locking. > > > For tables etc the invalidation handling works because we hold a lock on the > relation before modifying the catalog and don't release that lock until > transaction end. That part is crucial: We queue shared invalidations at > transaction commit, *after* the transaction is marked as visible, but *before* > locks are released. That guarantees that any backend processing invalidations > will see the new contents. However, if the lock on the modified object is > released before transaction commit, other backends can build and use a cache > entry that hasn't processed invalidations (invaliations are processed when > acquiring locks). > Right. > While there is such an object for publications, it seems to be acquired too > late to actually do much good in a number of paths. And not at all in others. > > E.g.: > > pubform = (Form_pg_publication) GETSTRUCT(tup); > > /* > * If the publication doesn't publish changes via the root partitioned > * table, the partition's row filter and column list will be used. So > * disallow using WHERE clause and column lists on partitioned table in > * this case. > */ > if (!pubform->puballtables && publish_via_partition_root_given && > !publish_via_partition_root) > { > /* > * Lock the publication so nobody else can do anything with it. This > * prevents concurrent alter to add partitioned table(s) with WHERE > * clause(s) and/or column lists which we don't allow when not > * publishing via root. > */ > LockDatabaseObject(PublicationRelationId, pubform->oid, 0, > AccessShareLock); > > a) Another session could have modified the publication and made puballtables out-of-date > b) The LockDatabaseObject() uses AccessShareLock, so others can get past this > point as well > > b) seems like a copy-paste bug or such? > > > I don't see any locking of the publication around RemovePublicationRelById(), > for example. > > I might just be misunderstanding things the way publication locking is > intended to work. > I've been asking similar questions while investigating this, but the interactions with logical decoding (which kinda happens concurrently in terms of WAL, but not concurrently in terms of time), historical snapshots etc. make my head spin. > >> However, while randomly poking at different things, I realized that if I >> change the lock obtained on the relation in OpenTableList() from >> ShareUpdateExclusiveLock to ShareRowExclusiveLock, the issue goes away. > > That's odd. There's cases where changing the lock level can cause invalidation > processing to happen because there is no pre-existing lock for the "new" lock > level, but there was for the old. But OpenTableList() is used when altering > the publications, so I don't see how that connects. > Yeah, I had the idea that maybe the transaction already holds the lock on the table, and changing this to ShareRowExclusiveLock makes it different, possibly triggering a new invalidation or something. But I did check with gdb, and if I set a breakpoint at OpenTableList, there are no locks on the table. But the effect is hard to deny - if I run the test 100 times, with the SharedUpdateExclusiveLock I get maybe 80 failures. After changing it to ShareRowExclusiveLock I get 0. Sure, there's some randomness for cases like this, but this is pretty unlikely. regards -- Tomas Vondra EnterpriseDB: http://www.enterprisedb.com The Enterprise PostgreSQL Company