Skip to content

Commit bc6bad8

Browse files
committed
Revert "WAL-log inplace update before revealing it to other sessions."
This reverts commit bfd5c6e (v17) and counterparts in each other non-master branch. This unblocks reverting a commit on which it depends. Discussion: https://postgr.es/m/10ec0bc3-5933-1189-6bb8-5dec4114558e@gmail.com
1 parent 0a0a0f2 commit bc6bad8

File tree

2 files changed

+16
-46
lines changed

2 files changed

+16
-46
lines changed

src/backend/access/heap/README.tuplock

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,4 +203,6 @@ Inplace updates create an exception to the rule that tuple data won't change
203203
under a reader holding a pin. A reader of a heap_fetch() result tuple may
204204
witness a torn read. Current inplace-updated fields are aligned and are no
205205
wider than four bytes, and current readers don't need consistency across
206-
fields. Hence, they get by with just fetching each field once.
206+
fields. Hence, they get by with just fetching each field once. XXX such a
207+
caller may also read a value that has not reached WAL; see
208+
systable_inplace_update_finish().

src/backend/access/heap/heapam.c

Lines changed: 13 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -6348,18 +6348,13 @@ heap_inplace_update_and_unlock(Relation relation,
63486348
HeapTupleHeader htup = oldtup->t_data;
63496349
uint32 oldlen;
63506350
uint32 newlen;
6351-
char *dst;
6352-
char *src;
63536351

63546352
Assert(ItemPointerEquals(&oldtup->t_self, &tuple->t_self));
63556353
oldlen = oldtup->t_len - htup->t_hoff;
63566354
newlen = tuple->t_len - tuple->t_data->t_hoff;
63576355
if (oldlen != newlen || htup->t_hoff != tuple->t_data->t_hoff)
63586356
elog(ERROR, "wrong tuple length");
63596357

6360-
dst = (char *) htup + htup->t_hoff;
6361-
src = (char *) tuple->t_data + tuple->t_data->t_hoff;
6362-
63636358
/*
63646359
* Construct shared cache inval if necessary. Note that because we only
63656360
* pass the new version of the tuple, this mustn't be used for any
@@ -6378,15 +6373,15 @@ heap_inplace_update_and_unlock(Relation relation,
63786373
*/
63796374
PreInplace_Inval();
63806375

6376+
/* NO EREPORT(ERROR) from here till changes are logged */
6377+
START_CRIT_SECTION();
6378+
6379+
memcpy((char *) htup + htup->t_hoff,
6380+
(char *) tuple->t_data + tuple->t_data->t_hoff,
6381+
newlen);
6382+
63816383
/*----------
6382-
* NO EREPORT(ERROR) from here till changes are complete
6383-
*
6384-
* Our buffer lock won't stop a reader having already pinned and checked
6385-
* visibility for this tuple. Hence, we write WAL first, then mutate the
6386-
* buffer. Like in MarkBufferDirtyHint() or RecordTransactionCommit(),
6387-
* checkpoint delay makes that acceptable. With the usual order of
6388-
* changes, a crash after memcpy() and before XLogInsert() could allow
6389-
* datfrozenxid to overtake relfrozenxid:
6384+
* XXX A crash here can allow datfrozenxid() to get ahead of relfrozenxid:
63906385
*
63916386
* ["D" is a VACUUM (ONLY_DATABASE_STATS)]
63926387
* ["R" is a VACUUM tbl]
@@ -6396,57 +6391,31 @@ heap_inplace_update_and_unlock(Relation relation,
63966391
* D: raise pg_database.datfrozenxid, XLogInsert(), finish
63976392
* [crash]
63986393
* [recovery restores datfrozenxid w/o relfrozenxid]
6399-
*
6400-
* Like in MarkBufferDirtyHint() subroutine XLogSaveBufferForHint(), copy
6401-
* the buffer to the stack before logging. Here, that facilitates a FPI
6402-
* of the post-mutation block before we accept other sessions seeing it.
64036394
*/
6404-
Assert((MyProc->delayChkptFlags & DELAY_CHKPT_START) == 0);
6405-
START_CRIT_SECTION();
6406-
MyProc->delayChkptFlags |= DELAY_CHKPT_START;
6395+
6396+
MarkBufferDirty(buffer);
64076397

64086398
/* XLOG stuff */
64096399
if (RelationNeedsWAL(relation))
64106400
{
64116401
xl_heap_inplace xlrec;
6412-
PGAlignedBlock copied_buffer;
6413-
char *origdata = (char *) BufferGetBlock(buffer);
6414-
Page page = BufferGetPage(buffer);
6415-
uint16 lower = ((PageHeader) page)->pd_lower;
6416-
uint16 upper = ((PageHeader) page)->pd_upper;
6417-
uintptr_t dst_offset_in_block;
6418-
RelFileLocator rlocator;
6419-
ForkNumber forkno;
6420-
BlockNumber blkno;
64216402
XLogRecPtr recptr;
64226403

64236404
xlrec.offnum = ItemPointerGetOffsetNumber(&tuple->t_self);
64246405

64256406
XLogBeginInsert();
64266407
XLogRegisterData((char *) &xlrec, SizeOfHeapInplace);
64276408

6428-
/* register block matching what buffer will look like after changes */
6429-
memcpy(copied_buffer.data, origdata, lower);
6430-
memcpy(copied_buffer.data + upper, origdata + upper, BLCKSZ - upper);
6431-
dst_offset_in_block = dst - origdata;
6432-
memcpy(copied_buffer.data + dst_offset_in_block, src, newlen);
6433-
BufferGetTag(buffer, &rlocator, &forkno, &blkno);
6434-
Assert(forkno == MAIN_FORKNUM);
6435-
XLogRegisterBlock(0, &rlocator, forkno, blkno, copied_buffer.data,
6436-
REGBUF_STANDARD);
6437-
XLogRegisterBufData(0, src, newlen);
6409+
XLogRegisterBuffer(0, buffer, REGBUF_STANDARD);
6410+
XLogRegisterBufData(0, (char *) htup + htup->t_hoff, newlen);
64386411

64396412
/* inplace updates aren't decoded atm, don't log the origin */
64406413

64416414
recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_INPLACE);
64426415

6443-
PageSetLSN(page, recptr);
6416+
PageSetLSN(BufferGetPage(buffer), recptr);
64446417
}
64456418

6446-
memcpy(dst, src, newlen);
6447-
6448-
MarkBufferDirty(buffer);
6449-
64506419
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
64516420

64526421
/*
@@ -6459,7 +6428,6 @@ heap_inplace_update_and_unlock(Relation relation,
64596428
*/
64606429
AtInplace_Inval();
64616430

6462-
MyProc->delayChkptFlags &= ~DELAY_CHKPT_START;
64636431
END_CRIT_SECTION();
64646432
UnlockTuple(relation, &tuple->t_self, InplaceUpdateTupleLock);
64656433

0 commit comments

Comments
 (0)