8
8
*
9
9
*
10
10
* IDENTIFICATION
11
- * $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.211 2006/03/31 23:32:05 tgl Exp $
11
+ * $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.212 2006/05/10 23:18:39 tgl Exp $
12
12
*
13
13
*
14
14
* INTERFACE ROUTINES
@@ -2673,6 +2673,97 @@ heap_lock_tuple(Relation relation, HeapTuple tuple, Buffer *buffer,
2673
2673
return HeapTupleMayBeUpdated ;
2674
2674
}
2675
2675
2676
+
2677
+ /*
2678
+ * heap_inplace_update - update a tuple "in place" (ie, overwrite it)
2679
+ *
2680
+ * Overwriting violates both MVCC and transactional safety, so the uses
2681
+ * of this function in Postgres are extremely limited. Nonetheless we
2682
+ * find some places to use it.
2683
+ *
2684
+ * The tuple cannot change size, and therefore it's reasonable to assume
2685
+ * that its null bitmap (if any) doesn't change either. So we just
2686
+ * overwrite the data portion of the tuple without touching the null
2687
+ * bitmap or any of the header fields.
2688
+ *
2689
+ * tuple is an in-memory tuple structure containing the data to be written
2690
+ * over the target tuple. Also, tuple->t_self identifies the target tuple.
2691
+ */
2692
+ void
2693
+ heap_inplace_update (Relation relation , HeapTuple tuple )
2694
+ {
2695
+ Buffer buffer ;
2696
+ Page page ;
2697
+ OffsetNumber offnum ;
2698
+ ItemId lp = NULL ;
2699
+ HeapTupleHeader htup ;
2700
+ uint32 oldlen ;
2701
+ uint32 newlen ;
2702
+
2703
+ buffer = ReadBuffer (relation , ItemPointerGetBlockNumber (& (tuple -> t_self )));
2704
+ LockBuffer (buffer , BUFFER_LOCK_EXCLUSIVE );
2705
+ page = (Page ) BufferGetPage (buffer );
2706
+
2707
+ offnum = ItemPointerGetOffsetNumber (& (tuple -> t_self ));
2708
+ if (PageGetMaxOffsetNumber (page ) >= offnum )
2709
+ lp = PageGetItemId (page , offnum );
2710
+
2711
+ if (PageGetMaxOffsetNumber (page ) < offnum || !ItemIdIsUsed (lp ))
2712
+ elog (ERROR , "heap_inplace_update: invalid lp" );
2713
+
2714
+ htup = (HeapTupleHeader ) PageGetItem (page , lp );
2715
+
2716
+ oldlen = ItemIdGetLength (lp ) - htup -> t_hoff ;
2717
+ newlen = tuple -> t_len - tuple -> t_data -> t_hoff ;
2718
+ if (oldlen != newlen || htup -> t_hoff != tuple -> t_data -> t_hoff )
2719
+ elog (ERROR , "heap_inplace_update: wrong tuple length" );
2720
+
2721
+ /* NO EREPORT(ERROR) from here till changes are logged */
2722
+ START_CRIT_SECTION ();
2723
+
2724
+ memcpy ((char * ) htup + htup -> t_hoff ,
2725
+ (char * ) tuple -> t_data + tuple -> t_data -> t_hoff ,
2726
+ newlen );
2727
+
2728
+ MarkBufferDirty (buffer );
2729
+
2730
+ /* XLOG stuff */
2731
+ if (!relation -> rd_istemp )
2732
+ {
2733
+ xl_heap_inplace xlrec ;
2734
+ XLogRecPtr recptr ;
2735
+ XLogRecData rdata [2 ];
2736
+
2737
+ xlrec .target .node = relation -> rd_node ;
2738
+ xlrec .target .tid = tuple -> t_self ;
2739
+
2740
+ rdata [0 ].data = (char * ) & xlrec ;
2741
+ rdata [0 ].len = SizeOfHeapInplace ;
2742
+ rdata [0 ].buffer = InvalidBuffer ;
2743
+ rdata [0 ].next = & (rdata [1 ]);
2744
+
2745
+ rdata [1 ].data = (char * ) htup + htup -> t_hoff ;
2746
+ rdata [1 ].len = newlen ;
2747
+ rdata [1 ].buffer = buffer ;
2748
+ rdata [1 ].buffer_std = true;
2749
+ rdata [1 ].next = NULL ;
2750
+
2751
+ recptr = XLogInsert (RM_HEAP_ID , XLOG_HEAP_INPLACE , rdata );
2752
+
2753
+ PageSetLSN (page , recptr );
2754
+ PageSetTLI (page , ThisTimeLineID );
2755
+ }
2756
+
2757
+ END_CRIT_SECTION ();
2758
+
2759
+ UnlockReleaseBuffer (buffer );
2760
+
2761
+ /* Send out shared cache inval if necessary */
2762
+ if (!IsBootstrapProcessingMode ())
2763
+ CacheInvalidateHeapTuple (relation , tuple );
2764
+ }
2765
+
2766
+
2676
2767
/* ----------------
2677
2768
* heap_markpos - mark scan position
2678
2769
* ----------------
@@ -3329,6 +3420,59 @@ heap_xlog_lock(XLogRecPtr lsn, XLogRecord *record)
3329
3420
UnlockReleaseBuffer (buffer );
3330
3421
}
3331
3422
3423
+ static void
3424
+ heap_xlog_inplace (XLogRecPtr lsn , XLogRecord * record )
3425
+ {
3426
+ xl_heap_inplace * xlrec = (xl_heap_inplace * ) XLogRecGetData (record );
3427
+ Relation reln = XLogOpenRelation (xlrec -> target .node );
3428
+ Buffer buffer ;
3429
+ Page page ;
3430
+ OffsetNumber offnum ;
3431
+ ItemId lp = NULL ;
3432
+ HeapTupleHeader htup ;
3433
+ uint32 oldlen ;
3434
+ uint32 newlen ;
3435
+
3436
+ if (record -> xl_info & XLR_BKP_BLOCK_1 )
3437
+ return ;
3438
+
3439
+ buffer = XLogReadBuffer (reln ,
3440
+ ItemPointerGetBlockNumber (& (xlrec -> target .tid )),
3441
+ false);
3442
+ if (!BufferIsValid (buffer ))
3443
+ return ;
3444
+ page = (Page ) BufferGetPage (buffer );
3445
+
3446
+ if (XLByteLE (lsn , PageGetLSN (page ))) /* changes are applied */
3447
+ {
3448
+ UnlockReleaseBuffer (buffer );
3449
+ return ;
3450
+ }
3451
+
3452
+ offnum = ItemPointerGetOffsetNumber (& (xlrec -> target .tid ));
3453
+ if (PageGetMaxOffsetNumber (page ) >= offnum )
3454
+ lp = PageGetItemId (page , offnum );
3455
+
3456
+ if (PageGetMaxOffsetNumber (page ) < offnum || !ItemIdIsUsed (lp ))
3457
+ elog (PANIC , "heap_inplace_redo: invalid lp" );
3458
+
3459
+ htup = (HeapTupleHeader ) PageGetItem (page , lp );
3460
+
3461
+ oldlen = ItemIdGetLength (lp ) - htup -> t_hoff ;
3462
+ newlen = record -> xl_len - SizeOfHeapInplace ;
3463
+ if (oldlen != newlen )
3464
+ elog (PANIC , "heap_inplace_redo: wrong tuple length" );
3465
+
3466
+ memcpy ((char * ) htup + htup -> t_hoff ,
3467
+ (char * ) xlrec + SizeOfHeapInplace ,
3468
+ newlen );
3469
+
3470
+ PageSetLSN (page , lsn );
3471
+ PageSetTLI (page , ThisTimeLineID );
3472
+ MarkBufferDirty (buffer );
3473
+ UnlockReleaseBuffer (buffer );
3474
+ }
3475
+
3332
3476
void
3333
3477
heap_redo (XLogRecPtr lsn , XLogRecord * record )
3334
3478
{
@@ -3349,6 +3493,8 @@ heap_redo(XLogRecPtr lsn, XLogRecord *record)
3349
3493
heap_xlog_newpage (lsn , record );
3350
3494
else if (info == XLOG_HEAP_LOCK )
3351
3495
heap_xlog_lock (lsn , record );
3496
+ else if (info == XLOG_HEAP_INPLACE )
3497
+ heap_xlog_inplace (lsn , record );
3352
3498
else
3353
3499
elog (PANIC , "heap_redo: unknown op code %u" , info );
3354
3500
}
@@ -3442,6 +3588,13 @@ heap_desc(StringInfo buf, uint8 xl_info, char *rec)
3442
3588
appendStringInfo (buf , "%u " , xlrec -> locking_xid );
3443
3589
out_target (buf , & (xlrec -> target ));
3444
3590
}
3591
+ else if (info == XLOG_HEAP_INPLACE )
3592
+ {
3593
+ xl_heap_inplace * xlrec = (xl_heap_inplace * ) rec ;
3594
+
3595
+ appendStringInfo (buf , "inplace: " );
3596
+ out_target (buf , & (xlrec -> target ));
3597
+ }
3445
3598
else
3446
3599
appendStringInfo (buf , "UNKNOWN" );
3447
3600
}
0 commit comments