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 1tE7ib-005IUC-Vt for pgsql-hackers@arkaria.postgresql.org; Thu, 21 Nov 2024 13:59:38 +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 1tE7ia-00FrvB-La for pgsql-hackers@arkaria.postgresql.org; Thu, 21 Nov 2024 13:59:36 +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.94.2) (envelope-from ) id 1tE7iZ-00Frv2-5n for pgsql-hackers@lists.postgresql.org; Thu, 21 Nov 2024 13:59:36 +0000 Received: from relay9-d.mail.gandi.net ([217.70.183.199]) by makus.postgresql.org with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1tE7iV-0033dG-Ag for pgsql-hackers@lists.postgresql.org; Thu, 21 Nov 2024 13:59:33 +0000 Received: by mail.gandi.net (Postfix) with ESMTPSA id 8B145FF803 for ; Thu, 21 Nov 2024 13:59:28 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=vondra.me; s=gm1; t=1732197568; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=uLdEbuYgD9UtCzDixq3S3j4T3WoggvE0ppCQmeXH7Wg=; b=IfZBvCFtNb1rPooh0qMFAZvdiQZ6+bb2lxwkUxX3qNjf2Kyn0I//k57fVSedDg05VUQ5NP yOCogQIRC2DtKhtLpUk353gBG5unDwNl1tNGKcc5CukBCLztvnKPCfl55kZnN324VmlDD7 8C3PUGnsyuVIueQCHkGa5MD2RvOxXbFG5sOsZ+1sw0w/d1dofw63P6fuhuP0uhd1vmNbK9 dL9xI0BjyDn1iJIVw0pdOaupeaLFf2xVIMNxaZz7h9XbCxUhs2Ai7b8SAbZP/8Gjd0Y4Z4 fpClSJ7S9TMod2SA+sMGroJ4FeafIrMALQLGBbKPbos594zp33xUY+5KVqebPg== Message-ID: Date: Thu, 21 Nov 2024 14:59:27 +0100 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: Re: Slot's restart_lsn may point to removed WAL segment after hard restart unexpectedly From: Tomas Vondra To: pgsql-hackers@lists.postgresql.org References: <1d12d2-67235980-35-19a406a0@63439497> <683f3c82-d38e-436d-88fd-27722af62005@vondra.me> <8679fea7-94ce-4a52-8e48-1a8cd0857fcb@vondra.me> Content-Language: en-US In-Reply-To: <8679fea7-94ce-4a52-8e48-1a8cd0857fcb@vondra.me> Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit X-GND-Sasl: tomas@vondra.me List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk On 11/20/24 23:19, Tomas Vondra wrote: > On 11/20/24 18:24, Tomas Vondra wrote: >> >> ... >> >> What confuses me a bit is that we update the restart_lsn (and call >> ReplicationSlotsComputeRequiredLSN() to recalculate the global value) >> all the time. Walsender does that in PhysicalConfirmReceivedLocation for >> example. So we actually see the required LSN to move during checkpoint >> very often. So how come we don't see the issues much more often? Surely >> I miss something important. >> > > This question "How come we don't see this more often?" kept bugging me, > and the answer is actually pretty simple. > > The restart_lsn can move backwards after a hard restart (for the reasons > explained), but physical replication does not actually rely on that. The > replica keeps track of the LSN it received (well, it uses the same LSN), > and on reconnect it sends the startpoint to the primary. And the primary > just proceeds use that instead of the (stale) restart LSN for the slot. > And the startpoint is guaranteed (I think) to be at least restart_lsn. > > AFAICS this would work for pg_replication_slot_advance() too, that is if > you remember the last LSN the slot advanced to, it should be possible to > advance to it just fine. Of course, it requires a way to remember that > LSN, which for a replica is not an issue. But this just highlights we > can't rely on restart_lsn for this purpose. > I kept thinking about this (sorry it's this incremental), particularly if this applies to logical replication too. And AFAICS it does not, or at least not to this extent. For streaming, the subscriber sends the startpoint (just like physical replication), so it should be protected too. But then there's the SQL API - pg_logical_slot_get_changes(). And it turns out it ends up syncing the slot to disk pretty often, because for RUNNING_XACTS we call LogicalDecodingProcessRecord() + standby_decode(), which ends up calling SaveSlotToDisk(). And at the end we call LogicalConfirmReceivedLocation() for good measure, which saves the slot too, just to be sure. FWIW I suspect this still is not perfectly safe, because we may still crash / restart before the updated data.restart_lsn makes it to disk, but after it was already used to remove old WAL, although that's probably harder to hit. With streaming the subscriber will still send us the new startpoint, so that should not fail I think. But with the SQL API we probably can get into the "segment already removed" issues. I haven't tried reproducing this yet, I guess it should be possible using the injection points. Not sure when I get to this, though. In any case, doesn't this suggest SaveSlotToDisk() really is not that expensive, if we do it pretty often for logical replication? Which was presented as the main reason why pg_replication_slot_advance() doesn't do that. Maybe it should? If the advance is substantial I don't think it really matters, because there simply can't be that many of large advances. It amortizes, in a way. But even with smaller advances it should be fine, I think - if the goal is to not remove WAL prematurely, it's enough to flush when we move to the next segment. regards -- Tomas Vondra