<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Backup on Discovery notebook</title><link>https://fljd.in/en/tags/backup/</link><description>Recent content in Backup on Discovery notebook</description><generator>Hugo -- gohugo.io</generator><language>en</language><managingEditor>Florent Jardin</managingEditor><lastBuildDate>Thu, 02 Dec 2021 00:00:00 +0000</lastBuildDate><atom:link href="https://fljd.in/en/tags/backup/index.xml" rel="self" type="application/rss+xml"/><item><title>A brief history of backup label</title><link>https://fljd.in/en/2021/12/02/a-brief-history-of-backup-label/</link><pubDate>Thu, 02 Dec 2021 00:00:00 +0000</pubDate><author>Florent Jardin</author><guid>https://fljd.in/en/2021/12/02/a-brief-history-of-backup-label/</guid><description>&lt;p&gt;For a long time, I remained ignorant about &lt;a href="http://www.interdb.jp/pg/pgsql09.html" target="_blank" rel="noopener"&gt;transaction logging mechanisms&lt;/a&gt;
and PITR in PostgreSQL, although they were crucial in data durability. A better
understanding of these concepts would have helped me in a previous life, to be
more confident during a backup configuration and, well, during after-crash
intervention!&lt;/p&gt;
&lt;p&gt;By reading this post, I will come back to an amusing file that used to be a
topic of discussion over the past decade: the backup label file. What is it and
what is it used for? How has it be enhanced from its origin with PostgreSQL 8.0
and what could be expected from him over the next years?&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="once-upon-a-time-there-was-transaction-logging"&gt;Once upon a time there was transaction logging&lt;/h2&gt;
&lt;p&gt;As an introduction and to better understand this post, it seems good to me to
explain that each changing operation in PostgreSQL, like an &lt;code&gt;UPDATE&lt;/code&gt; or an &lt;code&gt;INSERT&lt;/code&gt;,
is written a first time on &lt;code&gt;COMMIT&lt;/code&gt; in a group of files, which is called &lt;em&gt;WAL&lt;/em&gt;
or &lt;strong&gt;transaction logs&lt;/strong&gt;. Taken together, these changes represent a low cost to
disk activity compared to random writings of others processes at work in PostgreSQL.&lt;/p&gt;
&lt;p&gt;Among them, the &lt;code&gt;checkpointer&lt;/code&gt; process ensures that new data in memory is permanently
synchronized in the data files and that at regular times called &lt;code&gt;CHECKPOINT&lt;/code&gt;. This
on-disk two-step writing provides excellent performance and ensures that modified
blocks are not lost when a transaction ends successfully.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://fljd.in/img/en/2021-12-asynchronous-writes.png" alt="Asynchroneous writes on disks"&gt;&lt;/p&gt;
&lt;p&gt;Because of transaction logging, all data files of our cluster are late on real
transactional workload, until the next &lt;code&gt;CHECKPOINT&lt;/code&gt; moment. In case of an unexpected
interruption (like a memory crash), dirty pages will be lost and data files are
called &lt;strong&gt;inconsistents&lt;/strong&gt;, as they contain data that can be too old or uncommitted.&lt;/p&gt;
&lt;p&gt;In such situations, cluster service will be able to restart by applying losted
changes thanks to transaction logs written in WAL files. This rebuilding process
of data files to their consistent state is simply called &lt;strong&gt;crash recovery&lt;/strong&gt;.&lt;/p&gt;
&lt;div class="message"&gt;In PostgreSQL 8.0 and above, this mecanism laid the foundation for priceless
functionalities, like Point In Time Recovery or standby replication with Log
Shipping to a secondary cluster.&lt;/div&gt;
&lt;p&gt;Whether after a crash or data restoration, data files must be consistent during
the startup stage in order to accept write access to data again. What a terrible
surprise when the startup fails with the following error:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;PANIC: could not locate a valid checkpoint record&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;At this moment of startup stage, the cluster does not find any consistent point
between data files and fails to look after the nearest checkpoint record. Without
transactions logs, crash recovery fails and stops. At this point, your nerves and
your backup policy are put to the test.&lt;/p&gt;
&lt;p&gt;To put it another way: in lacks of WAL or theirs archives, &lt;u&gt;your most
recent data is lost&lt;/u&gt;.&lt;/p&gt;
&lt;p&gt;… And &lt;a href="https://pgpedia.info/p/pg_resetwal.html" target="_blank" rel="noopener"&gt;pg_resetwal&lt;/a&gt; will not bring them back to you.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="and-comes-backup-label"&gt;And comes backup label&lt;/h2&gt;
&lt;p&gt;After this lovely warning, we will consider that the archiving of transaction logs
is no longer an option when you are making backups. Make sure that these archives
are stored in a secure place, or even a decentralized area so that they are
accessible by all standby clusters when you need to trigger your failover plan.&lt;/p&gt;
&lt;p&gt;For those who have reached this part of the post, you should not be too lost if
I tell you that the &lt;em&gt;backup label&lt;/em&gt; file is a component of a larger concept called:
backup.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The backup history file is just a small text file. It contains the label string
you gave to &lt;code&gt;pg_basebackup&lt;/code&gt;, as well as the starting and ending times and WAL
segments of the backup. If you used the label to identify the associated dump
file, then the archived history file is enough to tell you which dump file to
restore.&lt;/p&gt;
&lt;p&gt;Source: &lt;a href="https://www.postgresql.org/docs/13/continuous-archiving.html#BACKUP-BASE-BACKUP" target="_blank" rel="noopener"&gt;Making a Base Backup&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Let’s see the simplest behavior of this documentation-praised tool &lt;a href="https://www.postgresql.org/docs/13/app-pgbasebackup.html" target="_blank" rel="noopener"&gt;pg_basebackup&lt;/a&gt;
by creating a &lt;code&gt;tar&lt;/code&gt; archive of my running cluster.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pg_basebackup --label=demo --pgdata=backups --format=tar \
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --checkpoint=fast --verbose
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pg_basebackup: initiating base backup, waiting for checkpoint to complete
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pg_basebackup: checkpoint completed
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pg_basebackup: write-ahead log start point: 0/16000028 on timeline 1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pg_basebackup: starting background WAL receiver
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pg_basebackup: created temporary replication slot &amp;#34;pg_basebackup_15594&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pg_basebackup: write-ahead log end point: 0/16000100
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pg_basebackup: waiting for background process to finish streaming ...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pg_basebackup: syncing data to disk ...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pg_basebackup: renaming backup_manifest.tmp to backup_manifest
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pg_basebackup: base backup completed
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Since version 10, option &lt;code&gt;--wal-method&lt;/code&gt; is setted on &lt;code&gt;stream&lt;/code&gt; by default, which
means that all present and future WAL segments in subdirectory &lt;code&gt;pg_wal&lt;/code&gt; will be
written in a dedicated archive next to the backup, thanks to a temporary
replication slot.&lt;/p&gt;
&lt;p&gt;Since version 13, this tool creates a new manifest backup file in order to verify
the integrity of our backup with &lt;a href="https://pgpedia.info/p/pg_verifybackup.html" target="_blank" rel="noopener"&gt;pg_verifybackup&lt;/a&gt;. Let&amp;rsquo;s explore our working
directory to find our long awaited backup label.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ tree backups/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;backups/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── backup_manifest
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── base.tar
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;└── pg_wal.tar
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ tar -xf backups/base.tar --to-stdout backup_label
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;START WAL LOCATION: 0/16000028 (file 000000010000000000000016)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;CHECKPOINT LOCATION: 0/16000060
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;BACKUP METHOD: streamed
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;BACKUP FROM: master
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;START TIME: 2021-01-18 15:22:52 CET
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;LABEL: demo
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;START TIMELINE: 1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This file is located in root&amp;rsquo;s archive and will be useful in startup process of
our cluster, since it contains the checkpoint information needed on a recovery
situation. In above example, the sequence number (LSN) is &lt;code&gt;0/16000060&lt;/code&gt; and will
be found in WAL &lt;code&gt;000000010000000000000016&lt;/code&gt;. In a lack of a backup label file,
startup process will only have the &lt;a href="https://pgpedia.info/p/pg_control.html" target="_blank" rel="noopener"&gt;control file&lt;/a&gt; to obtain the most recent
checkpoint, with no guarantee that it is the right one.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="the-glory-age"&gt;The glory age&lt;/h2&gt;
&lt;p&gt;You will agree with me that content and interest of the backup label file are
anecdotal (though essential) in backup architecture with PostgreSQL. It is (just)
a few-lines text file, only needed in some recovery processes.&lt;/p&gt;
&lt;p&gt;And yet, this small revolution caused by version 8.0 in January 2005 with its
new functionality, continuous archiving and PITR mecanism, aroused the
creativity of development team in the years that followed. The backup label
evolved to gain modularity and stability.&lt;/p&gt;
&lt;p&gt;At this time, &lt;code&gt;pg_backbackup&lt;/code&gt; was not yet available, and only an explicit call
to the function &lt;a href="https://pgpedia.info/p/pg_start_backup.html" target="_blank" rel="noopener"&gt;pg_start_backup()&lt;/a&gt; allowed you to generate the &lt;code&gt;backup_label&lt;/code&gt;
file in which were the &lt;a href="https://github.com/postgres/postgres/blob/REL8_0_STABLE/src/backend/access/transam/xlog.c#L5411" target="_blank" rel="noopener"&gt;following&lt;/a&gt; four entries to support hot backup:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;# backend/access/transam/xlog.c
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;fprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;START WAL LOCATION: %X/%X (file %s)&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;startpoint&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;xlogid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;startpoint&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;xrecoff&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;xlogfilename&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;fprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;CHECKPOINT LOCATION: %X/%X&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;checkpointloc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;xlogid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;checkpointloc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;xrecoff&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;fprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;START TIME: %s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;strfbuf&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;fprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;LABEL: %s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;backupidstr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;All next versions brought various fixes or enhancements. Among the notable
contributions, I selected for you:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://www.postgresql.org/message-id/flat/D960CB61B694CF459DCFB4B0128514C201ED284B%40exadv11.host.magwien.gv.at" target="_blank" rel="noopener"&gt;Contribution&lt;/a&gt; from Laurenz Albe (commit &lt;a href="https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=c979a1fefafcc83553bf218c7f2270cad77ea31d" target="_blank" rel="noopener"&gt;c979a1fe&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;Published with 8.4 version, &lt;code&gt;xlog.c&lt;/code&gt; codefile is extended with an internal
method to cancel a running backup. Calling the &lt;code&gt;pg_ctl stop&lt;/code&gt; command in &lt;em&gt;fast&lt;/em&gt;
mode renames the file to &lt;code&gt;backup_label.old&lt;/code&gt;;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://www.postgresql.org/message-id/flat/20120624213341.GA90986%40mr-paradox.net" target="_blank" rel="noopener"&gt;Contribution&lt;/a&gt; from Dave Kerr (commit &lt;a href="https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=0f04fc67f71f7cb29ccedb2e7ddf443b9e52b958" target="_blank" rel="noopener"&gt;0f04fc67&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;Appeared with 9.0.9 minor version, the &lt;code&gt;pg_start_backup()&lt;/code&gt; method includes a
&lt;code&gt;fsync()&lt;/code&gt; call ensures the backup label to be written to disk. This commit
guarantees the consistency of the backup during an external snapshot;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://www.postgresql.org/message-id/flat/4E40F710.6000404%40enterprisedb.com" target="_blank" rel="noopener"&gt;Contribution&lt;/a&gt; from Heikki Linnakangas (commit &lt;a href="https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=41f9ffd928b6fdcedd685483e777b0fa71ece47c" target="_blank" rel="noopener"&gt;41f9ffd9&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;Proposed in 9.2, this patch fix abnormal behaviors on restoration from
the streaming backup functionality. Backup label contains a new line that
specify the method used between &lt;code&gt;pg_start_backup&lt;/code&gt; or &lt;code&gt;streamed&lt;/code&gt;;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://www.postgresql.org/message-id/flat/201108050646.p756kHC5023570%40ccmds32.silk.ntts.co.jp" target="_blank" rel="noopener"&gt;Contribution&lt;/a&gt; from Jun Ishizuka and Fujii Masao (commit &lt;a href="https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=8366c7803ec3d0591cf2d1226fea1fee947d56c3" target="_blank" rel="noopener"&gt;8366c780&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;With 9.2 and above, &lt;code&gt;pg_start_backup()&lt;/code&gt; can be executed on a secondary
cluster. The role (&lt;code&gt;standby&lt;/code&gt; or &lt;code&gt;master&lt;/code&gt;) of the instance from which the backup
comes is retained in the backup label;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://www.postgresql.org/message-id/flat/CAB7nPqRosJNapKVW2QPwkN9%2BypfL4yiR4mcNFZcjxS2c8m%2BVkw%40mail.gmail.com" target="_blank" rel="noopener"&gt;Contribution&lt;/a&gt; from Michael Paquier (commit &lt;a href="https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=6271fceb8a4f07dafe9d67dcf7e849b319bb2647" target="_blank" rel="noopener"&gt;6271fceb&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;Added in 11, a new &lt;em&gt;timeline&lt;/em&gt; entry in backup label file joined the
previous information to compare its value with thoses contained in WAL needed
by recovery process;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As you may understand, during an amount of years, the ability to take a consistent
backup leaded on two distinct ways: &lt;code&gt;pg_start_backup()&lt;/code&gt; and &lt;code&gt;pg_basebackup&lt;/code&gt;. The
first and historical one was deeply impacted by regular commentaries about an
unwanted behavior with it &amp;ldquo;exclusive&amp;rdquo; mode.&lt;/p&gt;
&lt;p&gt;Let us look at an example with PostgreSQL 13:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pg_start_backup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;demo&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;-- pg_start_backup
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;-- -----------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;-- 0/1D000028
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ kill -ABRT $(head -1 data/postmaster.pid)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ cat data/backup_label
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;START WAL LOCATION: 0/1D000028 (file 00000001000000000000001D)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;CHECKPOINT LOCATION: 0/1D000060
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;BACKUP METHOD: pg_start_backup
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;BACKUP FROM: master
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;START TIME: 2021-01-18 16:49:57 CET
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;LABEL: demo
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;START TIMELINE: 1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;ABRT&lt;/code&gt; signal interrupts the &lt;code&gt;postmaster&lt;/code&gt; process of the cluster in the
violent way and an internal routine, called &lt;code&gt;CancelBackup&lt;/code&gt;, won&amp;rsquo;t be triggered
correctly in order to rename our backup label to &lt;code&gt;backup_label.old&lt;/code&gt;. On a normal
production workload, all transactions logs are recycled or even archived as
activity involves more new transactions. On restart of our interrupted instance,
the backup label inside data directory will be read by mistake with an errouneous
checkpoint record requested by the recovery process.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;LOG: database system was shut down at 2021-01-18 17:08:43 CET
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;LOG: invalid checkpoint record
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;FATAL: could not locate required checkpoint record
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;HINT: If you are restoring from a backup, touch &amp;#34;data/recovery.signal&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; and add required recovery options.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; If you are not restoring from a backup, try removing the file
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;data/backup_label&amp;#34;.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Be careful: removing &amp;#34;data/backup_label&amp;#34; will result in a corrupt
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; cluster if restoring from a backup.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;LOG: startup process (PID 19320) exited with exit code 1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;LOG: aborting startup due to startup process failure
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;LOG: database system is shut down
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The complete message only appeared with PostgreSQL 12 as an &lt;a href="https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=c900c15269f0f900d666bd1b0c6df3eff5098678" target="_blank" rel="noopener"&gt;explicite warning&lt;/a&gt;
in documentation of the backup label, following long discussions on throwing away
this particular mode or not. In one of theses threads, we can read a remarquable
&lt;a href="https://www.postgresql.org/message-id/CA&amp;#43;TgmoaGvpybE=xvJeg9Jc92c-9ikeVz3k-_Hg9=mdG05u=e=g@mail.gmail.com" target="_blank" rel="noopener"&gt;advocacy&lt;/a&gt; written by Robert Haas who looks back on the success of this
feature since its creation and points out the frequent confusion encountered by
users who do not understand either complexity or clear instructions from the
documentation.&lt;/p&gt;
&lt;p&gt;From these days of darkness, a dedicated note has been added.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This type of backup can only be taken on a primary and does not allow concurrent
backups. Moreover, because it creates a backup label file, as described below,
it can block automatic restart of the master server after a crash. On the other
hand, the erroneous removal of this file from a backup or standby is a common
mistake, which can result in serious data corruption.&lt;/p&gt;
&lt;p&gt;Source: &lt;a href="https://www.postgresql.org/docs/12/continuous-archiving.html#BACKUP-LOWLEVEL-BASE-BACKUP-EXCLUSIVE" target="_blank" rel="noopener"&gt;Making an Exclusive Low-Level Backup&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="next-generation"&gt;Next generation&lt;/h2&gt;
&lt;p&gt;This well-known drawback &lt;a href="https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=7117685461af50f50c03f43e6a622284c8d54694" target="_blank" rel="noopener"&gt;has been addressed&lt;/a&gt; by the development team in
september 2016 when releasing PostgreSQL 9.6 with &amp;ldquo;non-exclusive&amp;rdquo; backups. Since
then, exclusive backup mode is tagged as deprecated by developers and could be
removed in future versions.&lt;/p&gt;
&lt;p&gt;Backup label file has not been removed. Its content is still relevant in case of
point-in-time recovery, but it loses that transitory state on disk and won&amp;rsquo;t be
written in data directory on &lt;code&gt;pg_start_backup()&lt;/code&gt; call. Instead, administrator or
backup script must keep session opened until &lt;code&gt;pg_stop_backup()&lt;/code&gt; call in order to
collect backup&amp;rsquo;s metadata and rebuild backup label file needed by restoration
process.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pg_start_backup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;demo&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;exclusive&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fast&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;-- pg_start_backup
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;-- -----------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;-- 0/42000028
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;labelfile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pg_stop_backup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;exclusive&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;-- labelfile
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;-- ----------------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;-- START WAL LOCATION: 0/42000028 (file 000000010000000000000042)+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;-- CHECKPOINT LOCATION: 0/42000060 +
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;-- BACKUP METHOD: streamed +
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;-- BACKUP FROM: master +
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;-- START TIME: 2021-01-18 18:17:16 CET +
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;-- LABEL: demo +
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;-- START TIMELINE: 1 +
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There is another easy way to retrieve this content, especially if archiving is
configured. At the end of backup, metadata are written in a history file &lt;code&gt;.backup&lt;/code&gt;
inside &lt;code&gt;pg_wal&lt;/code&gt; and a &lt;code&gt;.ready&lt;/code&gt; file is added in &lt;code&gt;archive_status&lt;/code&gt; directory,
waiting for archiving. A quick search into our WAL repository can lead us to a
ready-to-use file.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ find archives -type f -not -size 16M
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;archives/000000010000000000000016.00000028.backup
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ grep -iv ^stop archives/000000010000000000000016.00000028.backup
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;START WAL LOCATION: 0/42000028 (file 000000010000000000000042)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;CHECKPOINT LOCATION: 0/42000060
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;BACKUP METHOD: streamed
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;BACKUP FROM: master
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;START TIME: 2021-01-18 18:17:16 CET
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;LABEL: demo
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;START TIMELINE: 1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With a fresh new architecture for non-exclusive concurrent backup system, various
backup tools have emerged, more powerful and modular than &lt;code&gt;pg_basebackup&lt;/code&gt;. Among
well-known third-party tools, you might hear of &lt;a href="https://pgbackrest.org/" target="_blank" rel="noopener"&gt;pgBackRest&lt;/a&gt; written in C,
&lt;a href="https://www.pgbarman.org/" target="_blank" rel="noopener"&gt;Barman&lt;/a&gt; written in Python, or even &lt;a href="https://dalibo.github.io/pitrery/" target="_blank" rel="noopener"&gt;pitrery&lt;/a&gt; written in Bash. Moreover, these
tools do a pretty well-done job, avoiding a painful effort for every administrator
in maintaining their complex scripts.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="moral-of-the-story"&gt;Moral of the story&lt;/h2&gt;
&lt;p&gt;Over releases, backup label file has endured many storms and twists to result in
a more elegant way to perform physical backup and restoration with PostgreSQL.&lt;/p&gt;
&lt;p&gt;If you are administrating database cluster, especially in virtualized engine,
I warmly recommend you to check your backup policies and associated tools. It is
not so uncommon for hypervisors to take a system snapshot in exclusive mode
with &lt;code&gt;pg_start_backup()&lt;/code&gt; as a pre-hook.&lt;/p&gt;
&lt;p&gt;Above specialized third-party softwares could/must be tested. If they do not fit
your needs, you may study others tricks to make our backups in a concurrent way,
as this &lt;a href="https://www.commandprompt.com/blog/postgresql-non-exclusive-base-Backup-bash/" target="_blank" rel="noopener"&gt;example&lt;/a&gt; with a temporary file made by &lt;code&gt;mkfifo&lt;/code&gt; command.&lt;/p&gt;
&lt;p&gt;Old-fashion exclusive backup is deprecated but not removed (yet). It is a real
concern that remains in a standstill, since last Commitfest in &lt;a href="https://commitfest.postgresql.org/28/1913/" target="_blank" rel="noopener"&gt;July 2020&lt;/a&gt;.
In a &lt;a href="https://www.postgresql.org/message-id/d4da3456-06a0-b790-fb07-036d0bd4bf0d%40pgmasters.net" target="_blank" rel="noopener"&gt;thread&lt;/a&gt;, contributor David Steele (who made pgBackRest, by the way)
suggested that backup label content could be stored in memory to fix its main
wickness:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It might be easier/better to just keep the one exclusive slot in shared
memory and store the backup label in it. We only allow one exclusive
backup now so it wouldn&amp;rsquo;t be a loss in functionality.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;To be continued!&lt;/p&gt;</description></item></channel></rss>