Re: ThisTimeLineID in checkpointer and bgwriter processes

From: Heikki Linnakangas <hlinnakangas(at)vmware(dot)com>
To: Amit Kapila <amit(dot)kapila(at)huawei(dot)com>
Cc: 'Fujii Masao' <masao(dot)fujii(at)gmail(dot)com>, 'PostgreSQL-development' <pgsql-hackers(at)postgresql(dot)org>
Subject: Re: ThisTimeLineID in checkpointer and bgwriter processes
Date: 2012-12-21 08:01:08
Message-ID: 50D41744.2020006@vmware.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

On 21.12.2012 08:18, Amit Kapila wrote:
> On Thursday, December 20, 2012 11:15 PM Heikki Linnakangas wrote:
>> On 20.12.2012 18:19, Fujii Masao wrote:
>>> InstallXLogFileSegment() also uses ThisTimeLineID. But your recent
>> commit
>>> doesn't take care of it and prevents the standby from recycling the
>> WAL files
>>> properly. Specifically, the standby recycles the WAL file to wrong
>> name.
>>
>> A-ha, good catch. So that's actually a live bug in 9.1 and 9.2 as well:
>> after the recovery target timeline has changed, restartpoints will
>> continue to preallocate/recycle WAL files for the old timeline. That's
>> otherwise harmless, but the useless WAL files waste space, and
>> walreceiver will have to always create new files.
>>
>> So instead of always running with ThisTimeLineID = 0 in the
>> checkpointer
>> process, I guess we'll have to update it to the timeline being
>> replayed,
>> when creating a restartpoint.
>
> Shouldn't there be a check if(RecoveryInProgress), before assigning
> RecoveryTargetTLI to ThisTimeLineID in CreateRestartPoint()?

Hmm, I don't think so. You're not supposed to get that far in
CreateRestartPoint() if recovery has already ended, or just being ended.
The startup process "ends recovery", ie. makes RecoveryInProgress()
return false, only after writing the end-of-recovery checkpoint. And
after the end-of-recovery checkpoint has been written,
CreateRestartPoint() will do nothing, because the end-of-recovery
checkpoint is later than the last potential restartpoint. I'm talking
about this check in CreateRestartPoint():

> if (XLogRecPtrIsInvalid(lastCheckPointRecPtr) ||
> XLByteLE(lastCheckPoint.redo, ControlFile->checkPointCopy.redo))
> {
> ereport(DEBUG2,
> (errmsg("skipping restartpoint, already performed at %X/%X",
> (uint32) (lastCheckPoint.redo >> 32), (uint32) lastCheckPoint.redo)));
> ...
> return false;
> }

However, there's this just before we recycle WAL segments:

> /*
> * Update pg_control, using current time. Check that it still shows
> * IN_ARCHIVE_RECOVERY state and an older checkpoint, else do nothing;
> * this is a quick hack to make sure nothing really bad happens if somehow
> * we get here after the end-of-recovery checkpoint.
> */
> LWLockAcquire(ControlFileLock, LW_EXCLUSIVE);
> if (ControlFile->state == DB_IN_ARCHIVE_RECOVERY &&
> XLByteLT(ControlFile->checkPointCopy.redo, lastCheckPoint.redo))
> {
> ...

but I believe that "quick hack" is just paranoia. You should not get
that far after the end-of-recovery checkpoint.

In any case, if you somehow get there anyway, the worst that will happen
is that some old WAL segments are recycled/preallocated on the old
timeline, wasting some space until the next checkpoint.

- Heikki

In response to

Browse pgsql-hackers by date

  From Date Subject
Next Message Simon Riggs 2012-12-21 08:56:07 Re: Review of Row Level Security
Previous Message Brett Maton 2012-12-21 07:02:11 Re: pg_top