Re: Buffer locking is special (hints, checksums, AIO writes)
Antonin Houska <ah@cybertec.at>
Andres Freund <andres@anarazel.de> wrote:
> > While troubleshooting REPACK issue [1], I realized that
> > HeapTupleSatisfiesMVCCBatch() can also be called during logical decoding - in
> > that case we need to use a historic MVCC snapshot.
>
> Huh. Indeed. That's unintentional - the path should never have been reached,
> we are checking that an MVCC snapshot is used. Unfortunately, somebody
> (i.e. probably me) at some point defined the relevant macro as
>
> /* This macro encodes the knowledge of which snapshots are MVCC-safe */
> #define IsMVCCSnapshot(snapshot) \
> ((snapshot)->snapshot_type == SNAPSHOT_MVCC || \
> (snapshot)->snapshot_type == SNAPSHOT_HISTORIC_MVCC)
>
> Which makes sense for some places, but not for plenty others.
>
> The reason this didn't cause more widespread issues is that during logical
> decoding we mostly don't use sequential scans etc that are affected by the
> these paths.
> > My proposal to fix the problem is attached.
>
> That's imo not at all the right fix - it'd make visibility during seqscans
> checking noticeably slower.
ok
> I think we ought to instead restrict the page-at-a-time scans to only happen
> with "real" mvcc snapshots. I.e. this:
>
> /*
> * Disable page-at-a-time mode if it's not a MVCC-safe snapshot.
> */
> if (!(snapshot && IsMVCCSnapshot(snapshot)))
> scan->rs_base.rs_flags &= ~SO_ALLOW_PAGEMODE;
>
> should trigger for historic snapshots as well.
I suppose you mean changing it to
if (!(snapshot && IsMVCCSnapshot(snapshot) &&
!IsHistoricMVCCSnapshot(snapshot)))
scan->rs_base.rs_flags &= ~SO_ALLOW_PAGEMODE;
> Does that fix the issue for you?
Yes, with this change, I don't hit the problem anymore.
> What's your reproducer?
Check out this branch
https://github.com/michail-nikolaev/postgres/tree/repack_concurrently_repro_22
and run t/008_repack_concurrently.pl in contrib/amcheck. The error we saw in
most cases was "ERROR: cache lookup failed for relation". I noticed that the
related pg_class entries had hint bits set incorrectly, so I added the
following to see when exactly it happens (actually I used lower elevel first,
to find out that the decoding worker is responsible for the problem):
diff --git a/src/backend/access/heap/heapam_visibility.c b/src/backend/access/heap/heapam_visibility.c
index 75ae268d753..ebf38460873 100644
--- a/src/backend/access/heap/heapam_visibility.c
+++ b/src/backend/access/heap/heapam_visibility.c
@@ -73,6 +73,7 @@
#include "access/transam.h"
#include "access/xact.h"
#include "access/xlog.h"
+#include "commands/cluster.h"
#include "storage/bufmgr.h"
#include "storage/procarray.h"
#include "utils/builtins.h"
@@ -938,6 +939,8 @@ HeapTupleSatisfiesMVCC(HeapTuple htup, Snapshot snapshot,
HeapTupleHeaderGetRawXmin(tuple));
else
{
+ if (am_decoding_for_repack())
+ elog(PANIC, "HEAP_XMIN_INVALID set");
/* it must have aborted or crashed */
SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
InvalidTransactionId);
The backtrace looked like:
#3 0x0000000000c367ad errfinish (postgres + 0x8367ad)
#4 0x0000000000517ee1 HeapTupleSatisfiesMVCC (postgres + 0x117ee1)
#5 0x0000000000518e14 HeapTupleSatisfiesMVCCBatch (postgres + 0x118e14)
#6 0x000000000050483e page_collect_tuples (postgres + 0x10483e)
#7 0x0000000000504a8e heap_prepare_pagescan (postgres + 0x104a8e)
#8 0x0000000000505344 heapgettup_pagemode (postgres + 0x105344)
#9 0x0000000000505cff heap_getnextslot (postgres + 0x105cff)
#10 0x000000000052ca08 table_scan_getnextslot (postgres + 0x12ca08)
#11 0x000000000052d4ed systable_getnext (postgres + 0x12d4ed)
#12 0x0000000000c2098e ScanPgRelation (postgres + 0x82098e)
#13 0x0000000000c23aa2 RelationReloadIndexInfo (postgres + 0x823aa2)
#14 0x0000000000c24376 RelationRebuildRelation (postgres + 0x824376)
#15 0x0000000000c23784 RelationIdGetRelation (postgres + 0x823784)
#16 0x00000000004b558f relation_open (postgres + 0xb558f)
#17 0x000000000052e073 index_open (postgres + 0x12e073)
#18 0x000000000052d0c5 systable_beginscan (postgres + 0x12d0c5)
#19 0x0000000000c2097e ScanPgRelation (postgres + 0x82097e)
#20 0x0000000000c23dde RelationReloadNailed (postgres + 0x823dde)
#21 0x0000000000c24399 RelationRebuildRelation (postgres + 0x824399)
#22 0x0000000000c23784 RelationIdGetRelation (postgres + 0x823784)
#23 0x00000000004b558f relation_open (postgres + 0xb558f)
#24 0x0000000000573ab1 table_open (postgres + 0x173ab1)
#25 0x0000000000c20919 ScanPgRelation (postgres + 0x820919)
#26 0x0000000000c21c98 RelationBuildDesc (postgres + 0x821c98)
#27 0x0000000000c237d6 RelationIdGetRelation (postgres + 0x8237d6)
#28 0x00000000009a028a ReorderBufferProcessTXN (postgres + 0x5a028a)
#29 0x00000000009a10ed ReorderBufferReplay (postgres + 0x5a10ed)
#30 0x00000000009a116b ReorderBufferCommit (postgres + 0x5a116b)
#31 0x000000000098c7fe DecodeCommit (postgres + 0x58c7fe)
#32 0x000000000098ba67 xact_decode (postgres + 0x58ba67)
#33 0x000000000098b685 LogicalDecodingProcessRecord (postgres + 0x58b685)
#34 0x00000000006a3e4b decode_concurrent_changes (postgres + 0x2a3e4b)
#35 0x00000000006a5ea3 repack_worker_internal (postgres + 0x2a5ea3)
#36 0x00000000006a5d5e RepackWorkerMain (postgres + 0x2a5d5e)
#37 0x0000000000961b2b BackgroundWorkerMain (postgres + 0x561b2b)
#38 0x0000000000964a61 postmaster_child_launch (postgres + 0x564a61)
#39 0x000000000096b58d StartBackgroundWorker (postgres + 0x56b58d)
#40 0x000000000096b80a maybe_start_bgworkers (postgres + 0x56b80a)
#41 0x000000000096a5d9 LaunchMissingBackgroundProcesses (postgres + 0x56a5d9)
#42 0x00000000009683fc ServerLoop (postgres + 0x5683fc)
#43 0x0000000000967d37 PostmasterMain (postgres + 0x567d37)
#44 0x0000000000813421 main (postgres + 0x413421)
Thanks.
--
Antonin Houska
Web: https://www.cybertec-postgresql.com
Commits
GET /api/v1/messages/:b64id/commits
the thread's linked commits as JSON, with link sources.
API reference →
-
bufmgr: Fix ordering of checks in PinBuffer()
- c0af4eb4e71e 19 (unreleased) landed
-
Use UnlockReleaseBuffer() in more places
- 8df3c48e466c 19 (unreleased) landed
-
bufmgr: Make UnlockReleaseBuffer() more efficient
- f39cb8c01106 19 (unreleased) landed
-
bufmgr: Don't copy pages while writing out
- 41d3d64e87af 19 (unreleased) landed
-
Fix use of wrong variable in _hash_kill_items()
- f5eb854ab6d6 19 (unreleased) landed
-
Fix bug due to confusion about what IsMVCCSnapshot means
- ce5d489166e5 19 (unreleased) landed
-
bufmgr: Switch to standard order in MarkBufferDirtyHint()
- a766125efd60 19 (unreleased) landed
-
bufmgr: Remove the, now obsolete, BM_JUST_DIRTIED
- b0f4ff3c9266 19 (unreleased) landed
-
Require share-exclusive lock to set hint bits and to flush
- 82467f627bd4 19 (unreleased) landed
-
heapam: Don't mimic MarkBufferDirtyHint() in inplace updates
- f4a4ce52c0d1 19 (unreleased) landed
-
bufmgr: Allow conditionally locking of already locked buffer
- 333f586372aa 19 (unreleased) landed
-
bufmgr: Avoid spurious compiler warning after fcb9c977aa5
- 84705b37273d 19 (unreleased) landed
-
lwlock: Remove ForEachLWLockHeldByMe
- 55fbfb738b00 19 (unreleased) landed
-
lwlock: Remove support for disowned lwlwocks
- d40fd85187d0 19 (unreleased) landed
-
bufmgr: Implement buffer content locks independently of lwlocks
- fcb9c977aa5f 19 (unreleased) landed
-
bufmgr: Change BufferDesc.state to be a 64-bit atomic
- dac328c8a682 19 (unreleased) landed
-
lwlock: Improve local variable name
- 556c92a68972 19 (unreleased) landed
-
lwlock: Invert meaning of LW_FLAG_RELEASE_OK
- 9a385f61666c 19 (unreleased) landed
-
bufmgr: Make definitions related to buffer descriptor easier to modify
- ff219c198789 19 (unreleased) landed
-
heapam: Add batch mode mvcc check and use it in page mode
- 0b96e734c590 19 (unreleased) landed
-
freespace: Don't modify page without any lock
- 45f658dacb9c 19 (unreleased) landed
-
heapam: Move logic to handle HEAP_MOVED into a helper function
- 548de59d93d5 19 (unreleased) landed
-
bufmgr: Optimize & harmonize LockBufHdr(), LWLockWaitListLock()
- 09ae2c8bac8d 19 (unreleased) landed
-
bufmgr: Add one-entry cache for private refcount
- 30df61990c67 19 (unreleased) landed
-
bufmgr: Separate keys for private refcount infrastructure
- edbaaea0a95e 19 (unreleased) landed
-
Add pg_atomic_unlocked_write_u64
- 7902a47c20b1 19 (unreleased) landed
-
Rename BUFFERPIN wait event class to BUFFER
- 6c5c393b7403 19 (unreleased) landed
-
bufmgr: Turn BUFFER_LOCK_* into an enum
- 156680055dc5 19 (unreleased) landed
-
lwlock: Fix, currently harmless, bug in LWLockWakeup()
- 81f773895321 19 (unreleased) landed
- da3971496531 15.16 landed
- 89c8a1b9069f 16.12 landed
- 427e886a79a5 17.8 landed
- 332693e75969 14.21 landed
- 8082b759d9b5 18.2 landed
-
bufmgr: Use atomic sub for unpinning buffers
- 5310fac6e0fc 19 (unreleased) landed
-
bufmgr: Allow some buffer state modifications while holding header lock
- c75ebc657ffc 19 (unreleased) landed
-
bufmgr: Fix valgrind checking for buffers pinned in StrategyGetBuffer()
- c819d1017ddb 19 (unreleased) landed
-
bufmgr: Don't lock buffer header in StrategyGetBuffer()
- 5e8998592879 19 (unreleased) landed
-
bufmgr: fewer calls to BufferDescriptorGetContentLock
- 3baae90013df 19 (unreleased) landed
-
bufmgr: Fix signedness of mask variable in BufferSync()
- 2a2e1b470b9b 19 (unreleased) landed
-
bufmgr: Introduce FlushUnlockedBuffer
- 3c2b97b29ee3 19 (unreleased) landed
-
Improve ReadRecentBuffer() scalability
- 819dc118c0f6 19 (unreleased) landed