00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041 #include "postgres.h"
00042
00043 #include "access/heapam.h"
00044 #include "access/heapam_xlog.h"
00045 #include "access/hio.h"
00046 #include "access/multixact.h"
00047 #include "access/relscan.h"
00048 #include "access/sysattr.h"
00049 #include "access/transam.h"
00050 #include "access/tuptoaster.h"
00051 #include "access/valid.h"
00052 #include "access/visibilitymap.h"
00053 #include "access/xact.h"
00054 #include "access/xlogutils.h"
00055 #include "catalog/catalog.h"
00056 #include "catalog/namespace.h"
00057 #include "miscadmin.h"
00058 #include "pgstat.h"
00059 #include "storage/bufmgr.h"
00060 #include "storage/freespace.h"
00061 #include "storage/lmgr.h"
00062 #include "storage/predicate.h"
00063 #include "storage/procarray.h"
00064 #include "storage/smgr.h"
00065 #include "storage/standby.h"
00066 #include "utils/datum.h"
00067 #include "utils/inval.h"
00068 #include "utils/lsyscache.h"
00069 #include "utils/relcache.h"
00070 #include "utils/snapmgr.h"
00071 #include "utils/syscache.h"
00072 #include "utils/tqual.h"
00073
00074
00075
00076 bool synchronize_seqscans = true;
00077
00078
00079 static HeapScanDesc heap_beginscan_internal(Relation relation,
00080 Snapshot snapshot,
00081 int nkeys, ScanKey key,
00082 bool allow_strat, bool allow_sync,
00083 bool is_bitmapscan);
00084 static HeapTuple heap_prepare_insert(Relation relation, HeapTuple tup,
00085 TransactionId xid, CommandId cid, int options);
00086 static XLogRecPtr log_heap_update(Relation reln, Buffer oldbuf,
00087 Buffer newbuf, HeapTuple oldtup,
00088 HeapTuple newtup, bool all_visible_cleared,
00089 bool new_all_visible_cleared);
00090 static void HeapSatisfiesHOTandKeyUpdate(Relation relation,
00091 Bitmapset *hot_attrs, Bitmapset *key_attrs,
00092 bool *satisfies_hot, bool *satisfies_key,
00093 HeapTuple oldtup, HeapTuple newtup);
00094 static void compute_new_xmax_infomask(TransactionId xmax, uint16 old_infomask,
00095 uint16 old_infomask2, TransactionId add_to_xmax,
00096 LockTupleMode mode, bool is_update,
00097 TransactionId *result_xmax, uint16 *result_infomask,
00098 uint16 *result_infomask2);
00099 static HTSU_Result heap_lock_updated_tuple(Relation rel, HeapTuple tuple,
00100 ItemPointer ctid, TransactionId xid,
00101 LockTupleMode mode);
00102 static void GetMultiXactIdHintBits(MultiXactId multi, uint16 *new_infomask,
00103 uint16 *new_infomask2);
00104 static TransactionId MultiXactIdGetUpdateXid(TransactionId xmax,
00105 uint16 t_infomask);
00106 static void MultiXactIdWait(MultiXactId multi, MultiXactStatus status,
00107 int *remaining, uint16 infomask);
00108 static bool ConditionalMultiXactIdWait(MultiXactId multi,
00109 MultiXactStatus status, int *remaining,
00110 uint16 infomask);
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120 static const struct
00121 {
00122 LOCKMODE hwlock;
00123 MultiXactStatus lockstatus;
00124 MultiXactStatus updstatus;
00125 }
00126 tupleLockExtraInfo[MaxLockTupleMode + 1] =
00127 {
00128 {
00129 AccessShareLock,
00130 MultiXactStatusForKeyShare,
00131 -1
00132 },
00133 {
00134 RowShareLock,
00135 MultiXactStatusForShare,
00136 -1
00137 },
00138 {
00139 ExclusiveLock,
00140 MultiXactStatusForNoKeyUpdate,
00141 MultiXactStatusNoKeyUpdate
00142 },
00143 {
00144 AccessExclusiveLock,
00145 MultiXactStatusForUpdate,
00146 MultiXactStatusUpdate
00147 }
00148 };
00149
00150 #define LOCKMODE_from_mxstatus(status) \
00151 (tupleLockExtraInfo[TUPLOCK_from_mxstatus((status))].hwlock)
00152
00153
00154
00155
00156
00157
00158 #define LockTupleTuplock(rel, tup, mode) \
00159 LockTuple((rel), (tup), tupleLockExtraInfo[mode].hwlock)
00160 #define UnlockTupleTuplock(rel, tup, mode) \
00161 UnlockTuple((rel), (tup), tupleLockExtraInfo[mode].hwlock)
00162 #define ConditionalLockTupleTuplock(rel, tup, mode) \
00163 ConditionalLockTuple((rel), (tup), tupleLockExtraInfo[mode].hwlock)
00164
00165
00166
00167
00168
00169 static const int MultiXactStatusLock[MaxMultiXactStatus + 1] =
00170 {
00171 LockTupleKeyShare,
00172 LockTupleShare,
00173 LockTupleNoKeyExclusive,
00174 LockTupleExclusive,
00175 LockTupleNoKeyExclusive,
00176 LockTupleExclusive
00177 };
00178
00179
00180 #define TUPLOCK_from_mxstatus(status) \
00181 (MultiXactStatusLock[(status)])
00182
00183 #define ISUPDATE_from_mxstatus(status) \
00184 ((status) > MultiXactStatusForUpdate)
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195 static void
00196 initscan(HeapScanDesc scan, ScanKey key, bool is_rescan)
00197 {
00198 bool allow_strat;
00199 bool allow_sync;
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212 scan->rs_nblocks = RelationGetNumberOfBlocks(scan->rs_rd);
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225 if (!RelationUsesLocalBuffers(scan->rs_rd) &&
00226 scan->rs_nblocks > NBuffers / 4)
00227 {
00228 allow_strat = scan->rs_allow_strat;
00229 allow_sync = scan->rs_allow_sync;
00230 }
00231 else
00232 allow_strat = allow_sync = false;
00233
00234 if (allow_strat)
00235 {
00236 if (scan->rs_strategy == NULL)
00237 scan->rs_strategy = GetAccessStrategy(BAS_BULKREAD);
00238 }
00239 else
00240 {
00241 if (scan->rs_strategy != NULL)
00242 FreeAccessStrategy(scan->rs_strategy);
00243 scan->rs_strategy = NULL;
00244 }
00245
00246 if (is_rescan)
00247 {
00248
00249
00250
00251
00252
00253 scan->rs_syncscan = (allow_sync && synchronize_seqscans);
00254 }
00255 else if (allow_sync && synchronize_seqscans)
00256 {
00257 scan->rs_syncscan = true;
00258 scan->rs_startblock = ss_get_location(scan->rs_rd, scan->rs_nblocks);
00259 }
00260 else
00261 {
00262 scan->rs_syncscan = false;
00263 scan->rs_startblock = 0;
00264 }
00265
00266 scan->rs_inited = false;
00267 scan->rs_ctup.t_data = NULL;
00268 ItemPointerSetInvalid(&scan->rs_ctup.t_self);
00269 scan->rs_cbuf = InvalidBuffer;
00270 scan->rs_cblock = InvalidBlockNumber;
00271
00272
00273 ItemPointerSetInvalid(&(scan->rs_mctid));
00274
00275
00276
00277
00278
00279
00280 if (key != NULL)
00281 memcpy(scan->rs_key, key, scan->rs_nkeys * sizeof(ScanKeyData));
00282
00283
00284
00285
00286
00287 if (!scan->rs_bitmapscan)
00288 pgstat_count_heap_scan(scan->rs_rd);
00289 }
00290
00291
00292
00293
00294
00295
00296
00297
00298 static void
00299 heapgetpage(HeapScanDesc scan, BlockNumber page)
00300 {
00301 Buffer buffer;
00302 Snapshot snapshot;
00303 Page dp;
00304 int lines;
00305 int ntup;
00306 OffsetNumber lineoff;
00307 ItemId lpp;
00308 bool all_visible;
00309
00310 Assert(page < scan->rs_nblocks);
00311
00312
00313 if (BufferIsValid(scan->rs_cbuf))
00314 {
00315 ReleaseBuffer(scan->rs_cbuf);
00316 scan->rs_cbuf = InvalidBuffer;
00317 }
00318
00319
00320
00321
00322
00323
00324 CHECK_FOR_INTERRUPTS();
00325
00326
00327 scan->rs_cbuf = ReadBufferExtended(scan->rs_rd, MAIN_FORKNUM, page,
00328 RBM_NORMAL, scan->rs_strategy);
00329 scan->rs_cblock = page;
00330
00331 if (!scan->rs_pageatatime)
00332 return;
00333
00334 buffer = scan->rs_cbuf;
00335 snapshot = scan->rs_snapshot;
00336
00337
00338
00339
00340 Assert(TransactionIdIsValid(RecentGlobalXmin));
00341 heap_page_prune_opt(scan->rs_rd, buffer, RecentGlobalXmin);
00342
00343
00344
00345
00346
00347
00348 LockBuffer(buffer, BUFFER_LOCK_SHARE);
00349
00350 dp = (Page) BufferGetPage(buffer);
00351 lines = PageGetMaxOffsetNumber(dp);
00352 ntup = 0;
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374 all_visible = PageIsAllVisible(dp) && !snapshot->takenDuringRecovery;
00375
00376 for (lineoff = FirstOffsetNumber, lpp = PageGetItemId(dp, lineoff);
00377 lineoff <= lines;
00378 lineoff++, lpp++)
00379 {
00380 if (ItemIdIsNormal(lpp))
00381 {
00382 HeapTupleData loctup;
00383 bool valid;
00384
00385 loctup.t_data = (HeapTupleHeader) PageGetItem((Page) dp, lpp);
00386 loctup.t_len = ItemIdGetLength(lpp);
00387 ItemPointerSet(&(loctup.t_self), page, lineoff);
00388
00389 if (all_visible)
00390 valid = true;
00391 else
00392 valid = HeapTupleSatisfiesVisibility(&loctup, snapshot, buffer);
00393
00394 CheckForSerializableConflictOut(valid, scan->rs_rd, &loctup,
00395 buffer, snapshot);
00396
00397 if (valid)
00398 scan->rs_vistuples[ntup++] = lineoff;
00399 }
00400 }
00401
00402 LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
00403
00404 Assert(ntup <= MaxHeapTuplesPerPage);
00405 scan->rs_ntuples = ntup;
00406 }
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431 static void
00432 heapgettup(HeapScanDesc scan,
00433 ScanDirection dir,
00434 int nkeys,
00435 ScanKey key)
00436 {
00437 HeapTuple tuple = &(scan->rs_ctup);
00438 Snapshot snapshot = scan->rs_snapshot;
00439 bool backward = ScanDirectionIsBackward(dir);
00440 BlockNumber page;
00441 bool finished;
00442 Page dp;
00443 int lines;
00444 OffsetNumber lineoff;
00445 int linesleft;
00446 ItemId lpp;
00447
00448
00449
00450
00451 if (ScanDirectionIsForward(dir))
00452 {
00453 if (!scan->rs_inited)
00454 {
00455
00456
00457
00458 if (scan->rs_nblocks == 0)
00459 {
00460 Assert(!BufferIsValid(scan->rs_cbuf));
00461 tuple->t_data = NULL;
00462 return;
00463 }
00464 page = scan->rs_startblock;
00465 heapgetpage(scan, page);
00466 lineoff = FirstOffsetNumber;
00467 scan->rs_inited = true;
00468 }
00469 else
00470 {
00471
00472 page = scan->rs_cblock;
00473 lineoff =
00474 OffsetNumberNext(ItemPointerGetOffsetNumber(&(tuple->t_self)));
00475 }
00476
00477 LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE);
00478
00479 dp = (Page) BufferGetPage(scan->rs_cbuf);
00480 lines = PageGetMaxOffsetNumber(dp);
00481
00482
00483 linesleft = lines - lineoff + 1;
00484 }
00485 else if (backward)
00486 {
00487 if (!scan->rs_inited)
00488 {
00489
00490
00491
00492 if (scan->rs_nblocks == 0)
00493 {
00494 Assert(!BufferIsValid(scan->rs_cbuf));
00495 tuple->t_data = NULL;
00496 return;
00497 }
00498
00499
00500
00501
00502
00503
00504
00505 scan->rs_syncscan = false;
00506
00507 if (scan->rs_startblock > 0)
00508 page = scan->rs_startblock - 1;
00509 else
00510 page = scan->rs_nblocks - 1;
00511 heapgetpage(scan, page);
00512 }
00513 else
00514 {
00515
00516 page = scan->rs_cblock;
00517 }
00518
00519 LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE);
00520
00521 dp = (Page) BufferGetPage(scan->rs_cbuf);
00522 lines = PageGetMaxOffsetNumber(dp);
00523
00524 if (!scan->rs_inited)
00525 {
00526 lineoff = lines;
00527 scan->rs_inited = true;
00528 }
00529 else
00530 {
00531 lineoff =
00532 OffsetNumberPrev(ItemPointerGetOffsetNumber(&(tuple->t_self)));
00533 }
00534
00535
00536 linesleft = lineoff;
00537 }
00538 else
00539 {
00540
00541
00542
00543 if (!scan->rs_inited)
00544 {
00545 Assert(!BufferIsValid(scan->rs_cbuf));
00546 tuple->t_data = NULL;
00547 return;
00548 }
00549
00550 page = ItemPointerGetBlockNumber(&(tuple->t_self));
00551 if (page != scan->rs_cblock)
00552 heapgetpage(scan, page);
00553
00554
00555 dp = (Page) BufferGetPage(scan->rs_cbuf);
00556 lineoff = ItemPointerGetOffsetNumber(&(tuple->t_self));
00557 lpp = PageGetItemId(dp, lineoff);
00558 Assert(ItemIdIsNormal(lpp));
00559
00560 tuple->t_data = (HeapTupleHeader) PageGetItem((Page) dp, lpp);
00561 tuple->t_len = ItemIdGetLength(lpp);
00562
00563 return;
00564 }
00565
00566
00567
00568
00569
00570 lpp = PageGetItemId(dp, lineoff);
00571 for (;;)
00572 {
00573 while (linesleft > 0)
00574 {
00575 if (ItemIdIsNormal(lpp))
00576 {
00577 bool valid;
00578
00579 tuple->t_data = (HeapTupleHeader) PageGetItem((Page) dp, lpp);
00580 tuple->t_len = ItemIdGetLength(lpp);
00581 ItemPointerSet(&(tuple->t_self), page, lineoff);
00582
00583
00584
00585
00586 valid = HeapTupleSatisfiesVisibility(tuple,
00587 snapshot,
00588 scan->rs_cbuf);
00589
00590 CheckForSerializableConflictOut(valid, scan->rs_rd, tuple,
00591 scan->rs_cbuf, snapshot);
00592
00593 if (valid && key != NULL)
00594 HeapKeyTest(tuple, RelationGetDescr(scan->rs_rd),
00595 nkeys, key, valid);
00596
00597 if (valid)
00598 {
00599 LockBuffer(scan->rs_cbuf, BUFFER_LOCK_UNLOCK);
00600 return;
00601 }
00602 }
00603
00604
00605
00606
00607 --linesleft;
00608 if (backward)
00609 {
00610 --lpp;
00611 --lineoff;
00612 }
00613 else
00614 {
00615 ++lpp;
00616 ++lineoff;
00617 }
00618 }
00619
00620
00621
00622
00623
00624 LockBuffer(scan->rs_cbuf, BUFFER_LOCK_UNLOCK);
00625
00626
00627
00628
00629 if (backward)
00630 {
00631 finished = (page == scan->rs_startblock);
00632 if (page == 0)
00633 page = scan->rs_nblocks;
00634 page--;
00635 }
00636 else
00637 {
00638 page++;
00639 if (page >= scan->rs_nblocks)
00640 page = 0;
00641 finished = (page == scan->rs_startblock);
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655 if (scan->rs_syncscan)
00656 ss_report_location(scan->rs_rd, page);
00657 }
00658
00659
00660
00661
00662 if (finished)
00663 {
00664 if (BufferIsValid(scan->rs_cbuf))
00665 ReleaseBuffer(scan->rs_cbuf);
00666 scan->rs_cbuf = InvalidBuffer;
00667 scan->rs_cblock = InvalidBlockNumber;
00668 tuple->t_data = NULL;
00669 scan->rs_inited = false;
00670 return;
00671 }
00672
00673 heapgetpage(scan, page);
00674
00675 LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE);
00676
00677 dp = (Page) BufferGetPage(scan->rs_cbuf);
00678 lines = PageGetMaxOffsetNumber((Page) dp);
00679 linesleft = lines;
00680 if (backward)
00681 {
00682 lineoff = lines;
00683 lpp = PageGetItemId(dp, lines);
00684 }
00685 else
00686 {
00687 lineoff = FirstOffsetNumber;
00688 lpp = PageGetItemId(dp, FirstOffsetNumber);
00689 }
00690 }
00691 }
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706 static void
00707 heapgettup_pagemode(HeapScanDesc scan,
00708 ScanDirection dir,
00709 int nkeys,
00710 ScanKey key)
00711 {
00712 HeapTuple tuple = &(scan->rs_ctup);
00713 bool backward = ScanDirectionIsBackward(dir);
00714 BlockNumber page;
00715 bool finished;
00716 Page dp;
00717 int lines;
00718 int lineindex;
00719 OffsetNumber lineoff;
00720 int linesleft;
00721 ItemId lpp;
00722
00723
00724
00725
00726 if (ScanDirectionIsForward(dir))
00727 {
00728 if (!scan->rs_inited)
00729 {
00730
00731
00732
00733 if (scan->rs_nblocks == 0)
00734 {
00735 Assert(!BufferIsValid(scan->rs_cbuf));
00736 tuple->t_data = NULL;
00737 return;
00738 }
00739 page = scan->rs_startblock;
00740 heapgetpage(scan, page);
00741 lineindex = 0;
00742 scan->rs_inited = true;
00743 }
00744 else
00745 {
00746
00747 page = scan->rs_cblock;
00748 lineindex = scan->rs_cindex + 1;
00749 }
00750
00751 dp = (Page) BufferGetPage(scan->rs_cbuf);
00752 lines = scan->rs_ntuples;
00753
00754
00755 linesleft = lines - lineindex;
00756 }
00757 else if (backward)
00758 {
00759 if (!scan->rs_inited)
00760 {
00761
00762
00763
00764 if (scan->rs_nblocks == 0)
00765 {
00766 Assert(!BufferIsValid(scan->rs_cbuf));
00767 tuple->t_data = NULL;
00768 return;
00769 }
00770
00771
00772
00773
00774
00775
00776
00777 scan->rs_syncscan = false;
00778
00779 if (scan->rs_startblock > 0)
00780 page = scan->rs_startblock - 1;
00781 else
00782 page = scan->rs_nblocks - 1;
00783 heapgetpage(scan, page);
00784 }
00785 else
00786 {
00787
00788 page = scan->rs_cblock;
00789 }
00790
00791 dp = (Page) BufferGetPage(scan->rs_cbuf);
00792 lines = scan->rs_ntuples;
00793
00794 if (!scan->rs_inited)
00795 {
00796 lineindex = lines - 1;
00797 scan->rs_inited = true;
00798 }
00799 else
00800 {
00801 lineindex = scan->rs_cindex - 1;
00802 }
00803
00804
00805 linesleft = lineindex + 1;
00806 }
00807 else
00808 {
00809
00810
00811
00812 if (!scan->rs_inited)
00813 {
00814 Assert(!BufferIsValid(scan->rs_cbuf));
00815 tuple->t_data = NULL;
00816 return;
00817 }
00818
00819 page = ItemPointerGetBlockNumber(&(tuple->t_self));
00820 if (page != scan->rs_cblock)
00821 heapgetpage(scan, page);
00822
00823
00824 dp = (Page) BufferGetPage(scan->rs_cbuf);
00825 lineoff = ItemPointerGetOffsetNumber(&(tuple->t_self));
00826 lpp = PageGetItemId(dp, lineoff);
00827 Assert(ItemIdIsNormal(lpp));
00828
00829 tuple->t_data = (HeapTupleHeader) PageGetItem((Page) dp, lpp);
00830 tuple->t_len = ItemIdGetLength(lpp);
00831
00832
00833 Assert(scan->rs_cindex < scan->rs_ntuples);
00834 Assert(lineoff == scan->rs_vistuples[scan->rs_cindex]);
00835
00836 return;
00837 }
00838
00839
00840
00841
00842
00843 for (;;)
00844 {
00845 while (linesleft > 0)
00846 {
00847 lineoff = scan->rs_vistuples[lineindex];
00848 lpp = PageGetItemId(dp, lineoff);
00849 Assert(ItemIdIsNormal(lpp));
00850
00851 tuple->t_data = (HeapTupleHeader) PageGetItem((Page) dp, lpp);
00852 tuple->t_len = ItemIdGetLength(lpp);
00853 ItemPointerSet(&(tuple->t_self), page, lineoff);
00854
00855
00856
00857
00858 if (key != NULL)
00859 {
00860 bool valid;
00861
00862 HeapKeyTest(tuple, RelationGetDescr(scan->rs_rd),
00863 nkeys, key, valid);
00864 if (valid)
00865 {
00866 scan->rs_cindex = lineindex;
00867 return;
00868 }
00869 }
00870 else
00871 {
00872 scan->rs_cindex = lineindex;
00873 return;
00874 }
00875
00876
00877
00878
00879 --linesleft;
00880 if (backward)
00881 --lineindex;
00882 else
00883 ++lineindex;
00884 }
00885
00886
00887
00888
00889
00890 if (backward)
00891 {
00892 finished = (page == scan->rs_startblock);
00893 if (page == 0)
00894 page = scan->rs_nblocks;
00895 page--;
00896 }
00897 else
00898 {
00899 page++;
00900 if (page >= scan->rs_nblocks)
00901 page = 0;
00902 finished = (page == scan->rs_startblock);
00903
00904
00905
00906
00907
00908
00909
00910
00911
00912
00913
00914
00915
00916 if (scan->rs_syncscan)
00917 ss_report_location(scan->rs_rd, page);
00918 }
00919
00920
00921
00922
00923 if (finished)
00924 {
00925 if (BufferIsValid(scan->rs_cbuf))
00926 ReleaseBuffer(scan->rs_cbuf);
00927 scan->rs_cbuf = InvalidBuffer;
00928 scan->rs_cblock = InvalidBlockNumber;
00929 tuple->t_data = NULL;
00930 scan->rs_inited = false;
00931 return;
00932 }
00933
00934 heapgetpage(scan, page);
00935
00936 dp = (Page) BufferGetPage(scan->rs_cbuf);
00937 lines = scan->rs_ntuples;
00938 linesleft = lines;
00939 if (backward)
00940 lineindex = lines - 1;
00941 else
00942 lineindex = 0;
00943 }
00944 }
00945
00946
00947 #if defined(DISABLE_COMPLEX_MACRO)
00948
00949
00950
00951
00952 Datum
00953 fastgetattr(HeapTuple tup, int attnum, TupleDesc tupleDesc,
00954 bool *isnull)
00955 {
00956 return (
00957 (attnum) > 0 ?
00958 (
00959 (*(isnull) = false),
00960 HeapTupleNoNulls(tup) ?
00961 (
00962 (tupleDesc)->attrs[(attnum) - 1]->attcacheoff >= 0 ?
00963 (
00964 fetchatt((tupleDesc)->attrs[(attnum) - 1],
00965 (char *) (tup)->t_data + (tup)->t_data->t_hoff +
00966 (tupleDesc)->attrs[(attnum) - 1]->attcacheoff)
00967 )
00968 :
00969 nocachegetattr((tup), (attnum), (tupleDesc))
00970 )
00971 :
00972 (
00973 att_isnull((attnum) - 1, (tup)->t_data->t_bits) ?
00974 (
00975 (*(isnull) = true),
00976 (Datum) NULL
00977 )
00978 :
00979 (
00980 nocachegetattr((tup), (attnum), (tupleDesc))
00981 )
00982 )
00983 )
00984 :
00985 (
00986 (Datum) NULL
00987 )
00988 );
00989 }
00990 #endif
00991
00992
00993
00994
00995
00996
00997
00998
00999
01000
01001
01002
01003
01004
01005
01006
01007
01008
01009
01010
01011
01012 Relation
01013 relation_open(Oid relationId, LOCKMODE lockmode)
01014 {
01015 Relation r;
01016
01017 Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES);
01018
01019
01020 if (lockmode != NoLock)
01021 LockRelationOid(relationId, lockmode);
01022
01023
01024 r = RelationIdGetRelation(relationId);
01025
01026 if (!RelationIsValid(r))
01027 elog(ERROR, "could not open relation with OID %u", relationId);
01028
01029
01030 if (RelationUsesLocalBuffers(r))
01031 MyXactAccessedTempRel = true;
01032
01033 pgstat_initstats(r);
01034
01035 return r;
01036 }
01037
01038
01039
01040
01041
01042
01043
01044
01045 Relation
01046 try_relation_open(Oid relationId, LOCKMODE lockmode)
01047 {
01048 Relation r;
01049
01050 Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES);
01051
01052
01053 if (lockmode != NoLock)
01054 LockRelationOid(relationId, lockmode);
01055
01056
01057
01058
01059
01060 if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(relationId)))
01061 {
01062
01063 if (lockmode != NoLock)
01064 UnlockRelationOid(relationId, lockmode);
01065
01066 return NULL;
01067 }
01068
01069
01070 r = RelationIdGetRelation(relationId);
01071
01072 if (!RelationIsValid(r))
01073 elog(ERROR, "could not open relation with OID %u", relationId);
01074
01075
01076 if (RelationUsesLocalBuffers(r))
01077 MyXactAccessedTempRel = true;
01078
01079 pgstat_initstats(r);
01080
01081 return r;
01082 }
01083
01084
01085
01086
01087
01088
01089
01090 Relation
01091 relation_openrv(const RangeVar *relation, LOCKMODE lockmode)
01092 {
01093 Oid relOid;
01094
01095
01096
01097
01098
01099
01100
01101
01102
01103
01104
01105
01106 if (lockmode != NoLock)
01107 AcceptInvalidationMessages();
01108
01109
01110 relOid = RangeVarGetRelid(relation, lockmode, false);
01111
01112
01113 return relation_open(relOid, NoLock);
01114 }
01115
01116
01117
01118
01119
01120
01121
01122
01123
01124
01125 Relation
01126 relation_openrv_extended(const RangeVar *relation, LOCKMODE lockmode,
01127 bool missing_ok)
01128 {
01129 Oid relOid;
01130
01131
01132
01133
01134
01135 if (lockmode != NoLock)
01136 AcceptInvalidationMessages();
01137
01138
01139 relOid = RangeVarGetRelid(relation, lockmode, missing_ok);
01140
01141
01142 if (!OidIsValid(relOid))
01143 return NULL;
01144
01145
01146 return relation_open(relOid, NoLock);
01147 }
01148
01149
01150
01151
01152
01153
01154
01155
01156
01157
01158 void
01159 relation_close(Relation relation, LOCKMODE lockmode)
01160 {
01161 LockRelId relid = relation->rd_lockInfo.lockRelId;
01162
01163 Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES);
01164
01165
01166 RelationClose(relation);
01167
01168 if (lockmode != NoLock)
01169 UnlockRelationId(&relid, lockmode);
01170 }
01171
01172
01173
01174
01175
01176
01177
01178
01179
01180
01181
01182 Relation
01183 heap_open(Oid relationId, LOCKMODE lockmode)
01184 {
01185 Relation r;
01186
01187 r = relation_open(relationId, lockmode);
01188
01189 if (r->rd_rel->relkind == RELKIND_INDEX)
01190 ereport(ERROR,
01191 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
01192 errmsg("\"%s\" is an index",
01193 RelationGetRelationName(r))));
01194 else if (r->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
01195 ereport(ERROR,
01196 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
01197 errmsg("\"%s\" is a composite type",
01198 RelationGetRelationName(r))));
01199
01200 return r;
01201 }
01202
01203
01204
01205
01206
01207
01208
01209
01210 Relation
01211 heap_openrv(const RangeVar *relation, LOCKMODE lockmode)
01212 {
01213 Relation r;
01214
01215 r = relation_openrv(relation, lockmode);
01216
01217 if (r->rd_rel->relkind == RELKIND_INDEX)
01218 ereport(ERROR,
01219 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
01220 errmsg("\"%s\" is an index",
01221 RelationGetRelationName(r))));
01222 else if (r->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
01223 ereport(ERROR,
01224 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
01225 errmsg("\"%s\" is a composite type",
01226 RelationGetRelationName(r))));
01227
01228 return r;
01229 }
01230
01231
01232
01233
01234
01235
01236
01237
01238
01239 Relation
01240 heap_openrv_extended(const RangeVar *relation, LOCKMODE lockmode,
01241 bool missing_ok)
01242 {
01243 Relation r;
01244
01245 r = relation_openrv_extended(relation, lockmode, missing_ok);
01246
01247 if (r)
01248 {
01249 if (r->rd_rel->relkind == RELKIND_INDEX)
01250 ereport(ERROR,
01251 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
01252 errmsg("\"%s\" is an index",
01253 RelationGetRelationName(r))));
01254 else if (r->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
01255 ereport(ERROR,
01256 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
01257 errmsg("\"%s\" is a composite type",
01258 RelationGetRelationName(r))));
01259 }
01260
01261 return r;
01262 }
01263
01264
01265
01266
01267
01268
01269
01270
01271
01272
01273
01274
01275
01276
01277
01278
01279 HeapScanDesc
01280 heap_beginscan(Relation relation, Snapshot snapshot,
01281 int nkeys, ScanKey key)
01282 {
01283 return heap_beginscan_internal(relation, snapshot, nkeys, key,
01284 true, true, false);
01285 }
01286
01287 HeapScanDesc
01288 heap_beginscan_strat(Relation relation, Snapshot snapshot,
01289 int nkeys, ScanKey key,
01290 bool allow_strat, bool allow_sync)
01291 {
01292 return heap_beginscan_internal(relation, snapshot, nkeys, key,
01293 allow_strat, allow_sync, false);
01294 }
01295
01296 HeapScanDesc
01297 heap_beginscan_bm(Relation relation, Snapshot snapshot,
01298 int nkeys, ScanKey key)
01299 {
01300 return heap_beginscan_internal(relation, snapshot, nkeys, key,
01301 false, false, true);
01302 }
01303
01304 static HeapScanDesc
01305 heap_beginscan_internal(Relation relation, Snapshot snapshot,
01306 int nkeys, ScanKey key,
01307 bool allow_strat, bool allow_sync,
01308 bool is_bitmapscan)
01309 {
01310 HeapScanDesc scan;
01311
01312
01313
01314
01315
01316
01317
01318
01319 RelationIncrementReferenceCount(relation);
01320
01321
01322
01323
01324 scan = (HeapScanDesc) palloc(sizeof(HeapScanDescData));
01325
01326 scan->rs_rd = relation;
01327 scan->rs_snapshot = snapshot;
01328 scan->rs_nkeys = nkeys;
01329 scan->rs_bitmapscan = is_bitmapscan;
01330 scan->rs_strategy = NULL;
01331 scan->rs_allow_strat = allow_strat;
01332 scan->rs_allow_sync = allow_sync;
01333
01334
01335
01336
01337 scan->rs_pageatatime = IsMVCCSnapshot(snapshot);
01338
01339
01340
01341
01342
01343
01344
01345
01346
01347
01348
01349
01350 if (!is_bitmapscan)
01351 PredicateLockRelation(relation, snapshot);
01352
01353
01354 scan->rs_ctup.t_tableOid = RelationGetRelid(relation);
01355
01356
01357
01358
01359
01360 if (nkeys > 0)
01361 scan->rs_key = (ScanKey) palloc(sizeof(ScanKeyData) * nkeys);
01362 else
01363 scan->rs_key = NULL;
01364
01365 initscan(scan, key, false);
01366
01367 return scan;
01368 }
01369
01370
01371
01372
01373
01374 void
01375 heap_rescan(HeapScanDesc scan,
01376 ScanKey key)
01377 {
01378
01379
01380
01381 if (BufferIsValid(scan->rs_cbuf))
01382 ReleaseBuffer(scan->rs_cbuf);
01383
01384
01385
01386
01387 initscan(scan, key, true);
01388 }
01389
01390
01391
01392
01393
01394
01395
01396
01397 void
01398 heap_endscan(HeapScanDesc scan)
01399 {
01400
01401
01402
01403
01404
01405 if (BufferIsValid(scan->rs_cbuf))
01406 ReleaseBuffer(scan->rs_cbuf);
01407
01408
01409
01410
01411 RelationDecrementReferenceCount(scan->rs_rd);
01412
01413 if (scan->rs_key)
01414 pfree(scan->rs_key);
01415
01416 if (scan->rs_strategy != NULL)
01417 FreeAccessStrategy(scan->rs_strategy);
01418
01419 pfree(scan);
01420 }
01421
01422
01423
01424
01425
01426
01427
01428
01429
01430
01431 #ifdef HEAPDEBUGALL
01432 #define HEAPDEBUG_1 \
01433 elog(DEBUG2, "heap_getnext([%s,nkeys=%d],dir=%d) called", \
01434 RelationGetRelationName(scan->rs_rd), scan->rs_nkeys, (int) direction)
01435 #define HEAPDEBUG_2 \
01436 elog(DEBUG2, "heap_getnext returning EOS")
01437 #define HEAPDEBUG_3 \
01438 elog(DEBUG2, "heap_getnext returning tuple")
01439 #else
01440 #define HEAPDEBUG_1
01441 #define HEAPDEBUG_2
01442 #define HEAPDEBUG_3
01443 #endif
01444
01445
01446 HeapTuple
01447 heap_getnext(HeapScanDesc scan, ScanDirection direction)
01448 {
01449
01450
01451 HEAPDEBUG_1;
01452
01453 if (scan->rs_pageatatime)
01454 heapgettup_pagemode(scan, direction,
01455 scan->rs_nkeys, scan->rs_key);
01456 else
01457 heapgettup(scan, direction, scan->rs_nkeys, scan->rs_key);
01458
01459 if (scan->rs_ctup.t_data == NULL)
01460 {
01461 HEAPDEBUG_2;
01462 return NULL;
01463 }
01464
01465
01466
01467
01468
01469 HEAPDEBUG_3;
01470
01471 pgstat_count_heap_getnext(scan->rs_rd);
01472
01473 return &(scan->rs_ctup);
01474 }
01475
01476
01477
01478
01479
01480
01481
01482
01483
01484
01485
01486
01487
01488
01489
01490
01491
01492
01493
01494
01495
01496
01497
01498
01499
01500
01501
01502
01503
01504
01505
01506
01507
01508
01509
01510
01511
01512
01513
01514 bool
01515 heap_fetch(Relation relation,
01516 Snapshot snapshot,
01517 HeapTuple tuple,
01518 Buffer *userbuf,
01519 bool keep_buf,
01520 Relation stats_relation)
01521 {
01522 ItemPointer tid = &(tuple->t_self);
01523 ItemId lp;
01524 Buffer buffer;
01525 Page page;
01526 OffsetNumber offnum;
01527 bool valid;
01528
01529
01530
01531
01532 buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));
01533
01534
01535
01536
01537 LockBuffer(buffer, BUFFER_LOCK_SHARE);
01538 page = BufferGetPage(buffer);
01539
01540
01541
01542
01543
01544 offnum = ItemPointerGetOffsetNumber(tid);
01545 if (offnum < FirstOffsetNumber || offnum > PageGetMaxOffsetNumber(page))
01546 {
01547 LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
01548 if (keep_buf)
01549 *userbuf = buffer;
01550 else
01551 {
01552 ReleaseBuffer(buffer);
01553 *userbuf = InvalidBuffer;
01554 }
01555 tuple->t_data = NULL;
01556 return false;
01557 }
01558
01559
01560
01561
01562 lp = PageGetItemId(page, offnum);
01563
01564
01565
01566
01567 if (!ItemIdIsNormal(lp))
01568 {
01569 LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
01570 if (keep_buf)
01571 *userbuf = buffer;
01572 else
01573 {
01574 ReleaseBuffer(buffer);
01575 *userbuf = InvalidBuffer;
01576 }
01577 tuple->t_data = NULL;
01578 return false;
01579 }
01580
01581
01582
01583
01584 tuple->t_data = (HeapTupleHeader) PageGetItem(page, lp);
01585 tuple->t_len = ItemIdGetLength(lp);
01586 tuple->t_tableOid = RelationGetRelid(relation);
01587
01588
01589
01590
01591 valid = HeapTupleSatisfiesVisibility(tuple, snapshot, buffer);
01592
01593 if (valid)
01594 PredicateLockTuple(relation, tuple, snapshot);
01595
01596 CheckForSerializableConflictOut(valid, relation, tuple, buffer, snapshot);
01597
01598 LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
01599
01600 if (valid)
01601 {
01602
01603
01604
01605
01606 *userbuf = buffer;
01607
01608
01609 if (stats_relation != NULL)
01610 pgstat_count_heap_fetch(stats_relation);
01611
01612 return true;
01613 }
01614
01615
01616 if (keep_buf)
01617 *userbuf = buffer;
01618 else
01619 {
01620 ReleaseBuffer(buffer);
01621 *userbuf = InvalidBuffer;
01622 }
01623
01624 return false;
01625 }
01626
01627
01628
01629
01630
01631
01632
01633
01634
01635
01636
01637
01638
01639
01640
01641
01642
01643
01644
01645
01646
01647
01648 bool
01649 heap_hot_search_buffer(ItemPointer tid, Relation relation, Buffer buffer,
01650 Snapshot snapshot, HeapTuple heapTuple,
01651 bool *all_dead, bool first_call)
01652 {
01653 Page dp = (Page) BufferGetPage(buffer);
01654 TransactionId prev_xmax = InvalidTransactionId;
01655 OffsetNumber offnum;
01656 bool at_chain_start;
01657 bool valid;
01658 bool skip;
01659
01660
01661 if (all_dead)
01662 *all_dead = first_call;
01663
01664 Assert(TransactionIdIsValid(RecentGlobalXmin));
01665
01666 Assert(ItemPointerGetBlockNumber(tid) == BufferGetBlockNumber(buffer));
01667 offnum = ItemPointerGetOffsetNumber(tid);
01668 at_chain_start = first_call;
01669 skip = !first_call;
01670
01671
01672 for (;;)
01673 {
01674 ItemId lp;
01675
01676
01677 if (offnum < FirstOffsetNumber || offnum > PageGetMaxOffsetNumber(dp))
01678 break;
01679
01680 lp = PageGetItemId(dp, offnum);
01681
01682
01683 if (!ItemIdIsNormal(lp))
01684 {
01685
01686 if (ItemIdIsRedirected(lp) && at_chain_start)
01687 {
01688
01689 offnum = ItemIdGetRedirect(lp);
01690 at_chain_start = false;
01691 continue;
01692 }
01693
01694 break;
01695 }
01696
01697 heapTuple->t_data = (HeapTupleHeader) PageGetItem(dp, lp);
01698 heapTuple->t_len = ItemIdGetLength(lp);
01699 heapTuple->t_tableOid = relation->rd_id;
01700 heapTuple->t_self = *tid;
01701
01702
01703
01704
01705 if (at_chain_start && HeapTupleIsHeapOnly(heapTuple))
01706 break;
01707
01708
01709
01710
01711
01712 if (TransactionIdIsValid(prev_xmax) &&
01713 !TransactionIdEquals(prev_xmax,
01714 HeapTupleHeaderGetXmin(heapTuple->t_data)))
01715 break;
01716
01717
01718
01719
01720
01721
01722
01723
01724 if (!skip)
01725 {
01726
01727 valid = HeapTupleSatisfiesVisibility(heapTuple, snapshot, buffer);
01728 CheckForSerializableConflictOut(valid, relation, heapTuple,
01729 buffer, snapshot);
01730 if (valid)
01731 {
01732 ItemPointerSetOffsetNumber(tid, offnum);
01733 PredicateLockTuple(relation, heapTuple, snapshot);
01734 if (all_dead)
01735 *all_dead = false;
01736 return true;
01737 }
01738 }
01739 skip = false;
01740
01741
01742
01743
01744
01745
01746 if (all_dead && *all_dead &&
01747 !HeapTupleIsSurelyDead(heapTuple->t_data, RecentGlobalXmin))
01748 *all_dead = false;
01749
01750
01751
01752
01753
01754 if (HeapTupleIsHotUpdated(heapTuple))
01755 {
01756 Assert(ItemPointerGetBlockNumber(&heapTuple->t_data->t_ctid) ==
01757 ItemPointerGetBlockNumber(tid));
01758 offnum = ItemPointerGetOffsetNumber(&heapTuple->t_data->t_ctid);
01759 at_chain_start = false;
01760 prev_xmax = HeapTupleHeaderGetUpdateXid(heapTuple->t_data);
01761 }
01762 else
01763 break;
01764 }
01765
01766 return false;
01767 }
01768
01769
01770
01771
01772
01773
01774
01775
01776 bool
01777 heap_hot_search(ItemPointer tid, Relation relation, Snapshot snapshot,
01778 bool *all_dead)
01779 {
01780 bool result;
01781 Buffer buffer;
01782 HeapTupleData heapTuple;
01783
01784 buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));
01785 LockBuffer(buffer, BUFFER_LOCK_SHARE);
01786 result = heap_hot_search_buffer(tid, relation, buffer, snapshot,
01787 &heapTuple, all_dead, true);
01788 LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
01789 ReleaseBuffer(buffer);
01790 return result;
01791 }
01792
01793
01794
01795
01796
01797
01798
01799
01800
01801
01802
01803
01804 void
01805 heap_get_latest_tid(Relation relation,
01806 Snapshot snapshot,
01807 ItemPointer tid)
01808 {
01809 BlockNumber blk;
01810 ItemPointerData ctid;
01811 TransactionId priorXmax;
01812
01813
01814 if (!ItemPointerIsValid(tid))
01815 return;
01816
01817
01818
01819
01820
01821
01822
01823 blk = ItemPointerGetBlockNumber(tid);
01824 if (blk >= RelationGetNumberOfBlocks(relation))
01825 elog(ERROR, "block number %u is out of range for relation \"%s\"",
01826 blk, RelationGetRelationName(relation));
01827
01828
01829
01830
01831
01832
01833
01834
01835
01836
01837 ctid = *tid;
01838 priorXmax = InvalidTransactionId;
01839 for (;;)
01840 {
01841 Buffer buffer;
01842 Page page;
01843 OffsetNumber offnum;
01844 ItemId lp;
01845 HeapTupleData tp;
01846 bool valid;
01847
01848
01849
01850
01851 buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(&ctid));
01852 LockBuffer(buffer, BUFFER_LOCK_SHARE);
01853 page = BufferGetPage(buffer);
01854
01855
01856
01857
01858
01859
01860 offnum = ItemPointerGetOffsetNumber(&ctid);
01861 if (offnum < FirstOffsetNumber || offnum > PageGetMaxOffsetNumber(page))
01862 {
01863 UnlockReleaseBuffer(buffer);
01864 break;
01865 }
01866 lp = PageGetItemId(page, offnum);
01867 if (!ItemIdIsNormal(lp))
01868 {
01869 UnlockReleaseBuffer(buffer);
01870 break;
01871 }
01872
01873
01874 tp.t_self = ctid;
01875 tp.t_data = (HeapTupleHeader) PageGetItem(page, lp);
01876 tp.t_len = ItemIdGetLength(lp);
01877
01878
01879
01880
01881
01882 if (TransactionIdIsValid(priorXmax) &&
01883 !TransactionIdEquals(priorXmax, HeapTupleHeaderGetXmin(tp.t_data)))
01884 {
01885 UnlockReleaseBuffer(buffer);
01886 break;
01887 }
01888
01889
01890
01891
01892
01893 valid = HeapTupleSatisfiesVisibility(&tp, snapshot, buffer);
01894 CheckForSerializableConflictOut(valid, relation, &tp, buffer, snapshot);
01895 if (valid)
01896 *tid = ctid;
01897
01898
01899
01900
01901 if ((tp.t_data->t_infomask & HEAP_XMAX_INVALID) ||
01902 HeapTupleHeaderIsOnlyLocked(tp.t_data) ||
01903 ItemPointerEquals(&tp.t_self, &tp.t_data->t_ctid))
01904 {
01905 UnlockReleaseBuffer(buffer);
01906 break;
01907 }
01908
01909 ctid = tp.t_data->t_ctid;
01910 priorXmax = HeapTupleHeaderGetUpdateXid(tp.t_data);
01911 UnlockReleaseBuffer(buffer);
01912 }
01913 }
01914
01915
01916
01917
01918
01919
01920
01921
01922
01923
01924
01925
01926
01927
01928
01929
01930
01931
01932 static void
01933 UpdateXmaxHintBits(HeapTupleHeader tuple, Buffer buffer, TransactionId xid)
01934 {
01935 Assert(TransactionIdEquals(HeapTupleHeaderGetRawXmax(tuple), xid));
01936 Assert(!(tuple->t_infomask & HEAP_XMAX_IS_MULTI));
01937
01938 if (!(tuple->t_infomask & (HEAP_XMAX_COMMITTED | HEAP_XMAX_INVALID)))
01939 {
01940 if (!HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask) &&
01941 TransactionIdDidCommit(xid))
01942 HeapTupleSetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
01943 xid);
01944 else
01945 HeapTupleSetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
01946 InvalidTransactionId);
01947 }
01948 }
01949
01950
01951
01952
01953
01954 BulkInsertState
01955 GetBulkInsertState(void)
01956 {
01957 BulkInsertState bistate;
01958
01959 bistate = (BulkInsertState) palloc(sizeof(BulkInsertStateData));
01960 bistate->strategy = GetAccessStrategy(BAS_BULKWRITE);
01961 bistate->current_buf = InvalidBuffer;
01962 return bistate;
01963 }
01964
01965
01966
01967
01968 void
01969 FreeBulkInsertState(BulkInsertState bistate)
01970 {
01971 if (bistate->current_buf != InvalidBuffer)
01972 ReleaseBuffer(bistate->current_buf);
01973 FreeAccessStrategy(bistate->strategy);
01974 pfree(bistate);
01975 }
01976
01977
01978
01979
01980
01981
01982
01983
01984
01985
01986
01987
01988
01989
01990
01991
01992
01993
01994
01995
01996
01997
01998
01999
02000
02001
02002
02003
02004
02005
02006
02007
02008
02009
02010
02011 Oid
02012 heap_insert(Relation relation, HeapTuple tup, CommandId cid,
02013 int options, BulkInsertState bistate)
02014 {
02015 TransactionId xid = GetCurrentTransactionId();
02016 HeapTuple heaptup;
02017 Buffer buffer;
02018 Buffer vmbuffer = InvalidBuffer;
02019 bool all_visible_cleared = false;
02020
02021
02022
02023
02024
02025
02026
02027
02028 heaptup = heap_prepare_insert(relation, tup, xid, cid, options);
02029
02030
02031
02032
02033
02034
02035
02036
02037
02038
02039
02040 CheckForSerializableConflictIn(relation, NULL, InvalidBuffer);
02041
02042
02043
02044
02045
02046 buffer = RelationGetBufferForTuple(relation, heaptup->t_len,
02047 InvalidBuffer, options, bistate,
02048 &vmbuffer, NULL);
02049
02050
02051 START_CRIT_SECTION();
02052
02053 RelationPutHeapTuple(relation, buffer, heaptup);
02054
02055 if (PageIsAllVisible(BufferGetPage(buffer)))
02056 {
02057 all_visible_cleared = true;
02058 PageClearAllVisible(BufferGetPage(buffer));
02059 visibilitymap_clear(relation,
02060 ItemPointerGetBlockNumber(&(heaptup->t_self)),
02061 vmbuffer);
02062 }
02063
02064
02065
02066
02067
02068
02069
02070
02071
02072
02073
02074
02075 MarkBufferDirty(buffer);
02076
02077
02078 if (!(options & HEAP_INSERT_SKIP_WAL) && RelationNeedsWAL(relation))
02079 {
02080 xl_heap_insert xlrec;
02081 xl_heap_header xlhdr;
02082 XLogRecPtr recptr;
02083 XLogRecData rdata[3];
02084 Page page = BufferGetPage(buffer);
02085 uint8 info = XLOG_HEAP_INSERT;
02086
02087 xlrec.all_visible_cleared = all_visible_cleared;
02088 xlrec.target.node = relation->rd_node;
02089 xlrec.target.tid = heaptup->t_self;
02090 rdata[0].data = (char *) &xlrec;
02091 rdata[0].len = SizeOfHeapInsert;
02092 rdata[0].buffer = InvalidBuffer;
02093 rdata[0].next = &(rdata[1]);
02094
02095 xlhdr.t_infomask2 = heaptup->t_data->t_infomask2;
02096 xlhdr.t_infomask = heaptup->t_data->t_infomask;
02097 xlhdr.t_hoff = heaptup->t_data->t_hoff;
02098
02099
02100
02101
02102
02103
02104 rdata[1].data = (char *) &xlhdr;
02105 rdata[1].len = SizeOfHeapHeader;
02106 rdata[1].buffer = buffer;
02107 rdata[1].buffer_std = true;
02108 rdata[1].next = &(rdata[2]);
02109
02110
02111 rdata[2].data = (char *) heaptup->t_data + offsetof(HeapTupleHeaderData, t_bits);
02112 rdata[2].len = heaptup->t_len - offsetof(HeapTupleHeaderData, t_bits);
02113 rdata[2].buffer = buffer;
02114 rdata[2].buffer_std = true;
02115 rdata[2].next = NULL;
02116
02117
02118
02119
02120
02121
02122 if (ItemPointerGetOffsetNumber(&(heaptup->t_self)) == FirstOffsetNumber &&
02123 PageGetMaxOffsetNumber(page) == FirstOffsetNumber)
02124 {
02125 info |= XLOG_HEAP_INIT_PAGE;
02126 rdata[1].buffer = rdata[2].buffer = InvalidBuffer;
02127 }
02128
02129 recptr = XLogInsert(RM_HEAP_ID, info, rdata);
02130
02131 PageSetLSN(page, recptr);
02132 }
02133
02134 END_CRIT_SECTION();
02135
02136 UnlockReleaseBuffer(buffer);
02137 if (vmbuffer != InvalidBuffer)
02138 ReleaseBuffer(vmbuffer);
02139
02140
02141
02142
02143
02144
02145
02146 CacheInvalidateHeapTuple(relation, heaptup, NULL);
02147
02148 pgstat_count_heap_insert(relation, 1);
02149
02150
02151
02152
02153
02154 if (heaptup != tup)
02155 {
02156 tup->t_self = heaptup->t_self;
02157 heap_freetuple(heaptup);
02158 }
02159
02160 return HeapTupleGetOid(tup);
02161 }
02162
02163
02164
02165
02166
02167
02168
02169
02170 static HeapTuple
02171 heap_prepare_insert(Relation relation, HeapTuple tup, TransactionId xid,
02172 CommandId cid, int options)
02173 {
02174 if (relation->rd_rel->relhasoids)
02175 {
02176 #ifdef NOT_USED
02177
02178 Assert(tup->t_data->t_infomask & HEAP_HASOID);
02179 #endif
02180
02181
02182
02183
02184
02185
02186
02187
02188
02189 if (!OidIsValid(HeapTupleGetOid(tup)))
02190 HeapTupleSetOid(tup, GetNewOid(relation));
02191 }
02192 else
02193 {
02194
02195 Assert(!(tup->t_data->t_infomask & HEAP_HASOID));
02196 }
02197
02198 tup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
02199 tup->t_data->t_infomask2 &= ~(HEAP2_XACT_MASK);
02200 tup->t_data->t_infomask |= HEAP_XMAX_INVALID;
02201 if (options & HEAP_INSERT_FROZEN)
02202 {
02203 tup->t_data->t_infomask |= HEAP_XMIN_COMMITTED;
02204 HeapTupleHeaderSetXmin(tup->t_data, FrozenTransactionId);
02205 }
02206 else
02207 HeapTupleHeaderSetXmin(tup->t_data, xid);
02208 HeapTupleHeaderSetCmin(tup->t_data, cid);
02209 HeapTupleHeaderSetXmax(tup->t_data, 0);
02210 tup->t_tableOid = RelationGetRelid(relation);
02211
02212
02213
02214
02215
02216 if (relation->rd_rel->relkind != RELKIND_RELATION &&
02217 relation->rd_rel->relkind != RELKIND_MATVIEW)
02218 {
02219
02220 Assert(!HeapTupleHasExternal(tup));
02221 return tup;
02222 }
02223 else if (HeapTupleHasExternal(tup) || tup->t_len > TOAST_TUPLE_THRESHOLD)
02224 return toast_insert_or_update(relation, tup, NULL, options);
02225 else
02226 return tup;
02227 }
02228
02229
02230
02231
02232
02233
02234
02235
02236
02237
02238
02239
02240 void
02241 heap_multi_insert(Relation relation, HeapTuple *tuples, int ntuples,
02242 CommandId cid, int options, BulkInsertState bistate)
02243 {
02244 TransactionId xid = GetCurrentTransactionId();
02245 HeapTuple *heaptuples;
02246 int i;
02247 int ndone;
02248 char *scratch = NULL;
02249 Page page;
02250 bool needwal;
02251 Size saveFreeSpace;
02252
02253 needwal = !(options & HEAP_INSERT_SKIP_WAL) && RelationNeedsWAL(relation);
02254 saveFreeSpace = RelationGetTargetPageFreeSpace(relation,
02255 HEAP_DEFAULT_FILLFACTOR);
02256
02257
02258 heaptuples = palloc(ntuples * sizeof(HeapTuple));
02259 for (i = 0; i < ntuples; i++)
02260 heaptuples[i] = heap_prepare_insert(relation, tuples[i],
02261 xid, cid, options);
02262
02263
02264
02265
02266
02267
02268 if (needwal)
02269 scratch = palloc(BLCKSZ);
02270
02271
02272
02273
02274
02275
02276
02277
02278
02279
02280
02281 CheckForSerializableConflictIn(relation, NULL, InvalidBuffer);
02282
02283 ndone = 0;
02284 while (ndone < ntuples)
02285 {
02286 Buffer buffer;
02287 Buffer vmbuffer = InvalidBuffer;
02288 bool all_visible_cleared = false;
02289 int nthispage;
02290
02291
02292
02293
02294
02295 buffer = RelationGetBufferForTuple(relation, heaptuples[ndone]->t_len,
02296 InvalidBuffer, options, bistate,
02297 &vmbuffer, NULL);
02298 page = BufferGetPage(buffer);
02299
02300
02301 START_CRIT_SECTION();
02302
02303
02304
02305
02306
02307 RelationPutHeapTuple(relation, buffer, heaptuples[ndone]);
02308 for (nthispage = 1; ndone + nthispage < ntuples; nthispage++)
02309 {
02310 HeapTuple heaptup = heaptuples[ndone + nthispage];
02311
02312 if (PageGetHeapFreeSpace(page) < MAXALIGN(heaptup->t_len) + saveFreeSpace)
02313 break;
02314
02315 RelationPutHeapTuple(relation, buffer, heaptup);
02316 }
02317
02318 if (PageIsAllVisible(page))
02319 {
02320 all_visible_cleared = true;
02321 PageClearAllVisible(page);
02322 visibilitymap_clear(relation,
02323 BufferGetBlockNumber(buffer),
02324 vmbuffer);
02325 }
02326
02327
02328
02329
02330
02331 MarkBufferDirty(buffer);
02332
02333
02334 if (needwal)
02335 {
02336 XLogRecPtr recptr;
02337 xl_heap_multi_insert *xlrec;
02338 XLogRecData rdata[2];
02339 uint8 info = XLOG_HEAP2_MULTI_INSERT;
02340 char *tupledata;
02341 int totaldatalen;
02342 char *scratchptr = scratch;
02343 bool init;
02344
02345
02346
02347
02348
02349 init = (ItemPointerGetOffsetNumber(&(heaptuples[ndone]->t_self)) == FirstOffsetNumber &&
02350 PageGetMaxOffsetNumber(page) == FirstOffsetNumber + nthispage - 1);
02351
02352
02353 xlrec = (xl_heap_multi_insert *) scratchptr;
02354 scratchptr += SizeOfHeapMultiInsert;
02355
02356
02357
02358
02359
02360
02361
02362 if (!init)
02363 scratchptr += nthispage * sizeof(OffsetNumber);
02364
02365
02366 tupledata = scratchptr;
02367
02368 xlrec->all_visible_cleared = all_visible_cleared;
02369 xlrec->node = relation->rd_node;
02370 xlrec->blkno = BufferGetBlockNumber(buffer);
02371 xlrec->ntuples = nthispage;
02372
02373
02374
02375
02376
02377 for (i = 0; i < nthispage; i++)
02378 {
02379 HeapTuple heaptup = heaptuples[ndone + i];
02380 xl_multi_insert_tuple *tuphdr;
02381 int datalen;
02382
02383 if (!init)
02384 xlrec->offsets[i] = ItemPointerGetOffsetNumber(&heaptup->t_self);
02385
02386 tuphdr = (xl_multi_insert_tuple *) SHORTALIGN(scratchptr);
02387 scratchptr = ((char *) tuphdr) + SizeOfMultiInsertTuple;
02388
02389 tuphdr->t_infomask2 = heaptup->t_data->t_infomask2;
02390 tuphdr->t_infomask = heaptup->t_data->t_infomask;
02391 tuphdr->t_hoff = heaptup->t_data->t_hoff;
02392
02393
02394 datalen = heaptup->t_len - offsetof(HeapTupleHeaderData, t_bits);
02395 memcpy(scratchptr,
02396 (char *) heaptup->t_data + offsetof(HeapTupleHeaderData, t_bits),
02397 datalen);
02398 tuphdr->datalen = datalen;
02399 scratchptr += datalen;
02400 }
02401 totaldatalen = scratchptr - tupledata;
02402 Assert((scratchptr - scratch) < BLCKSZ);
02403
02404 rdata[0].data = (char *) xlrec;
02405 rdata[0].len = tupledata - scratch;
02406 rdata[0].buffer = InvalidBuffer;
02407 rdata[0].next = &rdata[1];
02408
02409 rdata[1].data = tupledata;
02410 rdata[1].len = totaldatalen;
02411 rdata[1].buffer = buffer;
02412 rdata[1].buffer_std = true;
02413 rdata[1].next = NULL;
02414
02415
02416
02417
02418
02419 if (init)
02420 {
02421 rdata[1].buffer = InvalidBuffer;
02422 info |= XLOG_HEAP_INIT_PAGE;
02423 }
02424
02425 recptr = XLogInsert(RM_HEAP2_ID, info, rdata);
02426
02427 PageSetLSN(page, recptr);
02428 }
02429
02430 END_CRIT_SECTION();
02431
02432 UnlockReleaseBuffer(buffer);
02433 if (vmbuffer != InvalidBuffer)
02434 ReleaseBuffer(vmbuffer);
02435
02436 ndone += nthispage;
02437 }
02438
02439
02440
02441
02442
02443
02444
02445 if (IsSystemRelation(relation))
02446 {
02447 for (i = 0; i < ntuples; i++)
02448 CacheInvalidateHeapTuple(relation, heaptuples[i], NULL);
02449 }
02450
02451
02452
02453
02454
02455
02456 for (i = 0; i < ntuples; i++)
02457 tuples[i]->t_self = heaptuples[i]->t_self;
02458
02459 pgstat_count_heap_insert(relation, ntuples);
02460 }
02461
02462
02463
02464
02465
02466
02467
02468
02469
02470
02471 Oid
02472 simple_heap_insert(Relation relation, HeapTuple tup)
02473 {
02474 return heap_insert(relation, tup, GetCurrentCommandId(true), 0, NULL);
02475 }
02476
02477
02478
02479
02480
02481
02482
02483
02484 static uint8
02485 compute_infobits(uint16 infomask, uint16 infomask2)
02486 {
02487 return
02488 ((infomask & HEAP_XMAX_IS_MULTI) != 0 ? XLHL_XMAX_IS_MULTI : 0) |
02489 ((infomask & HEAP_XMAX_LOCK_ONLY) != 0 ? XLHL_XMAX_LOCK_ONLY : 0) |
02490 ((infomask & HEAP_XMAX_EXCL_LOCK) != 0 ? XLHL_XMAX_EXCL_LOCK : 0) |
02491
02492 ((infomask & HEAP_XMAX_KEYSHR_LOCK) != 0 ? XLHL_XMAX_KEYSHR_LOCK : 0) |
02493 ((infomask2 & HEAP_KEYS_UPDATED) != 0 ?
02494 XLHL_KEYS_UPDATED : 0);
02495 }
02496
02497
02498
02499
02500
02501
02502
02503
02504
02505
02506
02507
02508
02509
02510
02511
02512
02513
02514
02515
02516
02517
02518
02519
02520
02521
02522 HTSU_Result
02523 heap_delete(Relation relation, ItemPointer tid,
02524 CommandId cid, Snapshot crosscheck, bool wait,
02525 HeapUpdateFailureData *hufd)
02526 {
02527 HTSU_Result result;
02528 TransactionId xid = GetCurrentTransactionId();
02529 ItemId lp;
02530 HeapTupleData tp;
02531 Page page;
02532 BlockNumber block;
02533 Buffer buffer;
02534 Buffer vmbuffer = InvalidBuffer;
02535 TransactionId new_xmax;
02536 uint16 new_infomask,
02537 new_infomask2;
02538 bool have_tuple_lock = false;
02539 bool iscombo;
02540 bool all_visible_cleared = false;
02541
02542 Assert(ItemPointerIsValid(tid));
02543
02544 block = ItemPointerGetBlockNumber(tid);
02545 buffer = ReadBuffer(relation, block);
02546 page = BufferGetPage(buffer);
02547
02548
02549
02550
02551
02552
02553
02554 if (PageIsAllVisible(page))
02555 visibilitymap_pin(relation, block, &vmbuffer);
02556
02557 LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
02558
02559
02560
02561
02562
02563
02564
02565 if (vmbuffer == InvalidBuffer && PageIsAllVisible(page))
02566 {
02567 LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
02568 visibilitymap_pin(relation, block, &vmbuffer);
02569 LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
02570 }
02571
02572 lp = PageGetItemId(page, ItemPointerGetOffsetNumber(tid));
02573 Assert(ItemIdIsNormal(lp));
02574
02575 tp.t_data = (HeapTupleHeader) PageGetItem(page, lp);
02576 tp.t_len = ItemIdGetLength(lp);
02577 tp.t_self = *tid;
02578
02579 l1:
02580 result = HeapTupleSatisfiesUpdate(tp.t_data, cid, buffer);
02581
02582 if (result == HeapTupleInvisible)
02583 {
02584 UnlockReleaseBuffer(buffer);
02585 elog(ERROR, "attempted to delete invisible tuple");
02586 }
02587 else if (result == HeapTupleBeingUpdated && wait)
02588 {
02589 TransactionId xwait;
02590 uint16 infomask;
02591
02592
02593 xwait = HeapTupleHeaderGetRawXmax(tp.t_data);
02594 infomask = tp.t_data->t_infomask;
02595
02596 LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
02597
02598
02599
02600
02601
02602
02603
02604
02605
02606
02607 if (!have_tuple_lock)
02608 {
02609 LockTupleTuplock(relation, &(tp.t_self), LockTupleExclusive);
02610 have_tuple_lock = true;
02611 }
02612
02613
02614
02615
02616
02617
02618 if (infomask & HEAP_XMAX_IS_MULTI)
02619 {
02620
02621 MultiXactIdWait((MultiXactId) xwait, MultiXactStatusUpdate,
02622 NULL, infomask);
02623 LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
02624
02625
02626
02627
02628
02629
02630 if (!(tp.t_data->t_infomask & HEAP_XMAX_IS_MULTI) ||
02631 !TransactionIdEquals(HeapTupleHeaderGetRawXmax(tp.t_data),
02632 xwait))
02633 goto l1;
02634
02635
02636
02637
02638
02639
02640
02641
02642
02643
02644 }
02645 else
02646 {
02647
02648 XactLockTableWait(xwait);
02649 LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
02650
02651
02652
02653
02654
02655
02656 if ((tp.t_data->t_infomask & HEAP_XMAX_IS_MULTI) ||
02657 !TransactionIdEquals(HeapTupleHeaderGetRawXmax(tp.t_data),
02658 xwait))
02659 goto l1;
02660
02661
02662 UpdateXmaxHintBits(tp.t_data, buffer, xwait);
02663 }
02664
02665
02666
02667
02668
02669 if ((tp.t_data->t_infomask & HEAP_XMAX_INVALID) ||
02670 HEAP_XMAX_IS_LOCKED_ONLY(tp.t_data->t_infomask) ||
02671 HeapTupleHeaderIsOnlyLocked(tp.t_data))
02672 result = HeapTupleMayBeUpdated;
02673 else
02674 result = HeapTupleUpdated;
02675 }
02676
02677 if (crosscheck != InvalidSnapshot && result == HeapTupleMayBeUpdated)
02678 {
02679
02680 if (!HeapTupleSatisfiesVisibility(&tp, crosscheck, buffer))
02681 result = HeapTupleUpdated;
02682 }
02683
02684 if (result != HeapTupleMayBeUpdated)
02685 {
02686 Assert(result == HeapTupleSelfUpdated ||
02687 result == HeapTupleUpdated ||
02688 result == HeapTupleBeingUpdated);
02689 Assert(!(tp.t_data->t_infomask & HEAP_XMAX_INVALID));
02690 hufd->ctid = tp.t_data->t_ctid;
02691 hufd->xmax = HeapTupleHeaderGetUpdateXid(tp.t_data);
02692 if (result == HeapTupleSelfUpdated)
02693 hufd->cmax = HeapTupleHeaderGetCmax(tp.t_data);
02694 else
02695 hufd->cmax = 0;
02696 UnlockReleaseBuffer(buffer);
02697 if (have_tuple_lock)
02698 UnlockTupleTuplock(relation, &(tp.t_self), LockTupleExclusive);
02699 if (vmbuffer != InvalidBuffer)
02700 ReleaseBuffer(vmbuffer);
02701 return result;
02702 }
02703
02704
02705
02706
02707
02708 CheckForSerializableConflictIn(relation, &tp, buffer);
02709
02710
02711 HeapTupleHeaderAdjustCmax(tp.t_data, &cid, &iscombo);
02712
02713 START_CRIT_SECTION();
02714
02715
02716
02717
02718
02719
02720
02721
02722 PageSetPrunable(page, xid);
02723
02724 if (PageIsAllVisible(page))
02725 {
02726 all_visible_cleared = true;
02727 PageClearAllVisible(page);
02728 visibilitymap_clear(relation, BufferGetBlockNumber(buffer),
02729 vmbuffer);
02730 }
02731
02732
02733
02734
02735
02736
02737
02738
02739
02740
02741 MultiXactIdSetOldestMember();
02742
02743 compute_new_xmax_infomask(HeapTupleHeaderGetRawXmax(tp.t_data),
02744 tp.t_data->t_infomask, tp.t_data->t_infomask2,
02745 xid, LockTupleExclusive, true,
02746 &new_xmax, &new_infomask, &new_infomask2);
02747
02748
02749 tp.t_data->t_infomask &= ~(HEAP_XMAX_BITS | HEAP_MOVED);
02750 tp.t_data->t_infomask2 &= ~HEAP_KEYS_UPDATED;
02751 tp.t_data->t_infomask |= new_infomask;
02752 tp.t_data->t_infomask2 |= new_infomask2;
02753 HeapTupleHeaderClearHotUpdated(tp.t_data);
02754 HeapTupleHeaderSetXmax(tp.t_data, new_xmax);
02755 HeapTupleHeaderSetCmax(tp.t_data, cid, iscombo);
02756
02757 tp.t_data->t_ctid = tp.t_self;
02758
02759 MarkBufferDirty(buffer);
02760
02761
02762 if (RelationNeedsWAL(relation))
02763 {
02764 xl_heap_delete xlrec;
02765 XLogRecPtr recptr;
02766 XLogRecData rdata[2];
02767
02768 xlrec.all_visible_cleared = all_visible_cleared;
02769 xlrec.infobits_set = compute_infobits(tp.t_data->t_infomask,
02770 tp.t_data->t_infomask2);
02771 xlrec.target.node = relation->rd_node;
02772 xlrec.target.tid = tp.t_self;
02773 xlrec.xmax = new_xmax;
02774 rdata[0].data = (char *) &xlrec;
02775 rdata[0].len = SizeOfHeapDelete;
02776 rdata[0].buffer = InvalidBuffer;
02777 rdata[0].next = &(rdata[1]);
02778
02779 rdata[1].data = NULL;
02780 rdata[1].len = 0;
02781 rdata[1].buffer = buffer;
02782 rdata[1].buffer_std = true;
02783 rdata[1].next = NULL;
02784
02785 recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_DELETE, rdata);
02786
02787 PageSetLSN(page, recptr);
02788 }
02789
02790 END_CRIT_SECTION();
02791
02792 LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
02793
02794 if (vmbuffer != InvalidBuffer)
02795 ReleaseBuffer(vmbuffer);
02796
02797
02798
02799
02800
02801
02802
02803 if (relation->rd_rel->relkind != RELKIND_RELATION &&
02804 relation->rd_rel->relkind != RELKIND_MATVIEW)
02805 {
02806
02807 Assert(!HeapTupleHasExternal(&tp));
02808 }
02809 else if (HeapTupleHasExternal(&tp))
02810 toast_delete(relation, &tp);
02811
02812
02813
02814
02815
02816
02817 CacheInvalidateHeapTuple(relation, &tp, NULL);
02818
02819
02820 ReleaseBuffer(buffer);
02821
02822
02823
02824
02825 if (have_tuple_lock)
02826 UnlockTupleTuplock(relation, &(tp.t_self), LockTupleExclusive);
02827
02828 pgstat_count_heap_delete(relation);
02829
02830 return HeapTupleMayBeUpdated;
02831 }
02832
02833
02834
02835
02836
02837
02838
02839
02840
02841 void
02842 simple_heap_delete(Relation relation, ItemPointer tid)
02843 {
02844 HTSU_Result result;
02845 HeapUpdateFailureData hufd;
02846
02847 result = heap_delete(relation, tid,
02848 GetCurrentCommandId(true), InvalidSnapshot,
02849 true ,
02850 &hufd);
02851 switch (result)
02852 {
02853 case HeapTupleSelfUpdated:
02854
02855 elog(ERROR, "tuple already updated by self");
02856 break;
02857
02858 case HeapTupleMayBeUpdated:
02859
02860 break;
02861
02862 case HeapTupleUpdated:
02863 elog(ERROR, "tuple concurrently updated");
02864 break;
02865
02866 default:
02867 elog(ERROR, "unrecognized heap_delete status: %u", result);
02868 break;
02869 }
02870 }
02871
02872
02873
02874
02875
02876
02877
02878
02879
02880
02881
02882
02883
02884
02885
02886
02887
02888
02889
02890
02891
02892
02893
02894
02895
02896
02897
02898
02899
02900
02901
02902
02903
02904
02905 HTSU_Result
02906 heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
02907 CommandId cid, Snapshot crosscheck, bool wait,
02908 HeapUpdateFailureData *hufd, LockTupleMode *lockmode)
02909 {
02910 HTSU_Result result;
02911 TransactionId xid = GetCurrentTransactionId();
02912 Bitmapset *hot_attrs;
02913 Bitmapset *key_attrs;
02914 ItemId lp;
02915 HeapTupleData oldtup;
02916 HeapTuple heaptup;
02917 Page page;
02918 BlockNumber block;
02919 MultiXactStatus mxact_status;
02920 Buffer buffer,
02921 newbuf,
02922 vmbuffer = InvalidBuffer,
02923 vmbuffer_new = InvalidBuffer;
02924 bool need_toast,
02925 already_marked;
02926 Size newtupsize,
02927 pagefree;
02928 bool have_tuple_lock = false;
02929 bool iscombo;
02930 bool satisfies_hot;
02931 bool satisfies_key;
02932 bool use_hot_update = false;
02933 bool key_intact;
02934 bool all_visible_cleared = false;
02935 bool all_visible_cleared_new = false;
02936 bool checked_lockers;
02937 bool locker_remains;
02938 TransactionId xmax_new_tuple,
02939 xmax_old_tuple;
02940 uint16 infomask_old_tuple,
02941 infomask2_old_tuple,
02942 infomask_new_tuple,
02943 infomask2_new_tuple;
02944
02945 Assert(ItemPointerIsValid(otid));
02946
02947
02948
02949
02950
02951
02952
02953
02954
02955
02956
02957
02958
02959 hot_attrs = RelationGetIndexAttrBitmap(relation, false);
02960 key_attrs = RelationGetIndexAttrBitmap(relation, true);
02961
02962 block = ItemPointerGetBlockNumber(otid);
02963 buffer = ReadBuffer(relation, block);
02964 page = BufferGetPage(buffer);
02965
02966
02967
02968
02969
02970
02971
02972 if (PageIsAllVisible(page))
02973 visibilitymap_pin(relation, block, &vmbuffer);
02974
02975 LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
02976
02977 lp = PageGetItemId(page, ItemPointerGetOffsetNumber(otid));
02978 Assert(ItemIdIsNormal(lp));
02979
02980
02981
02982
02983
02984 oldtup.t_tableOid = RelationGetRelid(relation);
02985 oldtup.t_data = (HeapTupleHeader) PageGetItem(page, lp);
02986 oldtup.t_len = ItemIdGetLength(lp);
02987 oldtup.t_self = *otid;
02988
02989
02990 newtup->t_tableOid = RelationGetRelid(relation);
02991
02992
02993 if (relation->rd_rel->relhasoids)
02994 {
02995 #ifdef NOT_USED
02996
02997 Assert(newtup->t_data->t_infomask & HEAP_HASOID);
02998 #endif
02999 HeapTupleSetOid(newtup, HeapTupleGetOid(&oldtup));
03000 }
03001 else
03002 {
03003
03004 Assert(!(newtup->t_data->t_infomask & HEAP_HASOID));
03005 }
03006
03007
03008
03009
03010
03011
03012
03013
03014
03015
03016
03017
03018 HeapSatisfiesHOTandKeyUpdate(relation, hot_attrs, key_attrs,
03019 &satisfies_hot, &satisfies_key,
03020 &oldtup, newtup);
03021 if (satisfies_key)
03022 {
03023 *lockmode = LockTupleNoKeyExclusive;
03024 mxact_status = MultiXactStatusNoKeyUpdate;
03025 key_intact = true;
03026
03027
03028
03029
03030
03031
03032
03033
03034
03035
03036 MultiXactIdSetOldestMember();
03037 }
03038 else
03039 {
03040 *lockmode = LockTupleExclusive;
03041 mxact_status = MultiXactStatusUpdate;
03042 key_intact = false;
03043 }
03044
03045
03046
03047
03048
03049
03050
03051
03052 l2:
03053 checked_lockers = false;
03054 locker_remains = false;
03055 result = HeapTupleSatisfiesUpdate(oldtup.t_data, cid, buffer);
03056
03057
03058 Assert(result != HeapTupleBeingUpdated || wait);
03059
03060 if (result == HeapTupleInvisible)
03061 {
03062 UnlockReleaseBuffer(buffer);
03063 elog(ERROR, "attempted to update invisible tuple");
03064 }
03065 else if (result == HeapTupleBeingUpdated && wait)
03066 {
03067 TransactionId xwait;
03068 uint16 infomask;
03069 bool can_continue = false;
03070
03071 checked_lockers = true;
03072
03073
03074
03075
03076
03077
03078
03079
03080
03081
03082
03083
03084
03085
03086 xwait = HeapTupleHeaderGetRawXmax(oldtup.t_data);
03087 infomask = oldtup.t_data->t_infomask;
03088
03089 LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
03090
03091
03092
03093
03094
03095
03096
03097
03098
03099
03100 if (!have_tuple_lock)
03101 {
03102 LockTupleTuplock(relation, &(oldtup.t_self), *lockmode);
03103 have_tuple_lock = true;
03104 }
03105
03106
03107
03108
03109
03110
03111
03112
03113
03114
03115
03116
03117 if (infomask & HEAP_XMAX_IS_MULTI)
03118 {
03119 TransactionId update_xact;
03120 int remain;
03121
03122
03123 MultiXactIdWait((MultiXactId) xwait, mxact_status, &remain,
03124 infomask);
03125 LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
03126
03127
03128
03129
03130
03131
03132 if (!(oldtup.t_data->t_infomask & HEAP_XMAX_IS_MULTI) ||
03133 !TransactionIdEquals(HeapTupleHeaderGetRawXmax(oldtup.t_data),
03134 xwait))
03135 goto l2;
03136
03137
03138
03139
03140
03141
03142
03143
03144
03145
03146
03147
03148
03149
03150
03151
03152
03153
03154
03155
03156 update_xact = InvalidTransactionId;
03157 if (!HEAP_XMAX_IS_LOCKED_ONLY(oldtup.t_data->t_infomask))
03158 update_xact = HeapTupleGetUpdateXid(oldtup.t_data);
03159
03160
03161 if (!TransactionIdIsValid(update_xact) ||
03162 TransactionIdDidAbort(update_xact))
03163 can_continue = true;
03164
03165 locker_remains = remain != 0;
03166 }
03167 else
03168 {
03169
03170
03171
03172
03173
03174 if (HEAP_XMAX_IS_KEYSHR_LOCKED(infomask) && key_intact)
03175 {
03176 LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
03177
03178
03179
03180
03181
03182 if ((oldtup.t_data->t_infomask & HEAP_XMAX_IS_MULTI) ||
03183 !TransactionIdEquals(HeapTupleHeaderGetRawXmax(oldtup.t_data),
03184 xwait))
03185 goto l2;
03186
03187 can_continue = true;
03188 locker_remains = true;
03189 }
03190 else
03191 {
03192
03193 XactLockTableWait(xwait);
03194 LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
03195
03196
03197
03198
03199
03200
03201 if ((oldtup.t_data->t_infomask & HEAP_XMAX_IS_MULTI) ||
03202 !TransactionIdEquals(HeapTupleHeaderGetRawXmax(oldtup.t_data),
03203 xwait))
03204 goto l2;
03205
03206
03207 UpdateXmaxHintBits(oldtup.t_data, buffer, xwait);
03208 if (oldtup.t_data->t_infomask & HEAP_XMAX_INVALID)
03209 can_continue = true;
03210 }
03211 }
03212
03213 result = can_continue ? HeapTupleMayBeUpdated : HeapTupleUpdated;
03214 }
03215
03216 if (crosscheck != InvalidSnapshot && result == HeapTupleMayBeUpdated)
03217 {
03218
03219 if (!HeapTupleSatisfiesVisibility(&oldtup, crosscheck, buffer))
03220 result = HeapTupleUpdated;
03221 }
03222
03223 if (result != HeapTupleMayBeUpdated)
03224 {
03225 Assert(result == HeapTupleSelfUpdated ||
03226 result == HeapTupleUpdated ||
03227 result == HeapTupleBeingUpdated);
03228 Assert(!(oldtup.t_data->t_infomask & HEAP_XMAX_INVALID));
03229 hufd->ctid = oldtup.t_data->t_ctid;
03230 hufd->xmax = HeapTupleHeaderGetUpdateXid(oldtup.t_data);
03231 if (result == HeapTupleSelfUpdated)
03232 hufd->cmax = HeapTupleHeaderGetCmax(oldtup.t_data);
03233 else
03234 hufd->cmax = 0;
03235 UnlockReleaseBuffer(buffer);
03236 if (have_tuple_lock)
03237 UnlockTupleTuplock(relation, &(oldtup.t_self), *lockmode);
03238 if (vmbuffer != InvalidBuffer)
03239 ReleaseBuffer(vmbuffer);
03240 bms_free(hot_attrs);
03241 bms_free(key_attrs);
03242 return result;
03243 }
03244
03245
03246
03247
03248
03249
03250
03251
03252
03253
03254 if (vmbuffer == InvalidBuffer && PageIsAllVisible(page))
03255 {
03256 LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
03257 visibilitymap_pin(relation, block, &vmbuffer);
03258 LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
03259 goto l2;
03260 }
03261
03262
03263
03264
03265
03266 CheckForSerializableConflictIn(relation, &oldtup, buffer);
03267
03268
03269
03270
03271
03272
03273
03274 compute_new_xmax_infomask(HeapTupleHeaderGetRawXmax(oldtup.t_data),
03275 oldtup.t_data->t_infomask,
03276 oldtup.t_data->t_infomask2,
03277 xid, *lockmode, true,
03278 &xmax_old_tuple, &infomask_old_tuple,
03279 &infomask2_old_tuple);
03280
03281
03282
03283
03284
03285
03286
03287
03288 if ((oldtup.t_data->t_infomask & HEAP_XMAX_INVALID) ||
03289 (checked_lockers && !locker_remains))
03290 xmax_new_tuple = InvalidTransactionId;
03291 else
03292 xmax_new_tuple = HeapTupleHeaderGetRawXmax(oldtup.t_data);
03293
03294 if (!TransactionIdIsValid(xmax_new_tuple))
03295 {
03296 infomask_new_tuple = HEAP_XMAX_INVALID;
03297 infomask2_new_tuple = 0;
03298 }
03299 else
03300 {
03301
03302
03303
03304
03305
03306
03307 if (oldtup.t_data->t_infomask & HEAP_XMAX_IS_MULTI)
03308 {
03309 GetMultiXactIdHintBits(xmax_new_tuple, &infomask_new_tuple,
03310 &infomask2_new_tuple);
03311 }
03312 else
03313 {
03314 infomask_new_tuple = HEAP_XMAX_KEYSHR_LOCK | HEAP_XMAX_LOCK_ONLY;
03315 infomask2_new_tuple = 0;
03316 }
03317 }
03318
03319
03320
03321
03322
03323 newtup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
03324 newtup->t_data->t_infomask2 &= ~(HEAP2_XACT_MASK);
03325 HeapTupleHeaderSetXmin(newtup->t_data, xid);
03326 HeapTupleHeaderSetCmin(newtup->t_data, cid);
03327 newtup->t_data->t_infomask |= HEAP_UPDATED | infomask_new_tuple;
03328 newtup->t_data->t_infomask2 |= infomask2_new_tuple;
03329 HeapTupleHeaderSetXmax(newtup->t_data, xmax_new_tuple);
03330
03331
03332
03333
03334
03335 HeapTupleHeaderAdjustCmax(oldtup.t_data, &cid, &iscombo);
03336
03337
03338
03339
03340
03341
03342
03343
03344
03345
03346
03347
03348 if (relation->rd_rel->relkind != RELKIND_RELATION &&
03349 relation->rd_rel->relkind != RELKIND_MATVIEW)
03350 {
03351
03352 Assert(!HeapTupleHasExternal(&oldtup));
03353 Assert(!HeapTupleHasExternal(newtup));
03354 need_toast = false;
03355 }
03356 else
03357 need_toast = (HeapTupleHasExternal(&oldtup) ||
03358 HeapTupleHasExternal(newtup) ||
03359 newtup->t_len > TOAST_TUPLE_THRESHOLD);
03360
03361 pagefree = PageGetHeapFreeSpace(page);
03362
03363 newtupsize = MAXALIGN(newtup->t_len);
03364
03365 if (need_toast || newtupsize > pagefree)
03366 {
03367
03368 oldtup.t_data->t_infomask &= ~(HEAP_XMAX_BITS | HEAP_MOVED);
03369 oldtup.t_data->t_infomask2 &= ~HEAP_KEYS_UPDATED;
03370 HeapTupleClearHotUpdated(&oldtup);
03371
03372 Assert(TransactionIdIsValid(xmax_old_tuple));
03373 HeapTupleHeaderSetXmax(oldtup.t_data, xmax_old_tuple);
03374 oldtup.t_data->t_infomask |= infomask_old_tuple;
03375 oldtup.t_data->t_infomask2 |= infomask2_old_tuple;
03376 HeapTupleHeaderSetCmax(oldtup.t_data, cid, iscombo);
03377
03378 oldtup.t_data->t_ctid = oldtup.t_self;
03379 already_marked = true;
03380 LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
03381
03382
03383
03384
03385
03386
03387
03388
03389 if (need_toast)
03390 {
03391
03392 heaptup = toast_insert_or_update(relation, newtup, &oldtup, 0);
03393 newtupsize = MAXALIGN(heaptup->t_len);
03394 }
03395 else
03396 heaptup = newtup;
03397
03398
03399
03400
03401
03402
03403
03404
03405
03406
03407
03408
03409
03410
03411
03412
03413
03414
03415 if (newtupsize > pagefree)
03416 {
03417
03418 newbuf = RelationGetBufferForTuple(relation, heaptup->t_len,
03419 buffer, 0, NULL,
03420 &vmbuffer_new, &vmbuffer);
03421 }
03422 else
03423 {
03424
03425 LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
03426
03427 pagefree = PageGetHeapFreeSpace(page);
03428 if (newtupsize > pagefree)
03429 {
03430
03431
03432
03433
03434
03435 LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
03436 newbuf = RelationGetBufferForTuple(relation, heaptup->t_len,
03437 buffer, 0, NULL,
03438 &vmbuffer_new, &vmbuffer);
03439 }
03440 else
03441 {
03442
03443 newbuf = buffer;
03444 }
03445 }
03446 }
03447 else
03448 {
03449
03450 already_marked = false;
03451 newbuf = buffer;
03452 heaptup = newtup;
03453 }
03454
03455
03456
03457
03458
03459
03460
03461
03462
03463 CheckForSerializableConflictIn(relation, NULL, InvalidBuffer);
03464
03465
03466
03467
03468
03469
03470
03471 if (newbuf == buffer)
03472 {
03473
03474
03475
03476
03477
03478 if (satisfies_hot)
03479 use_hot_update = true;
03480 }
03481 else
03482 {
03483
03484 PageSetFull(page);
03485 }
03486
03487
03488 START_CRIT_SECTION();
03489
03490
03491
03492
03493
03494
03495
03496
03497
03498
03499
03500
03501
03502 PageSetPrunable(page, xid);
03503
03504 if (use_hot_update)
03505 {
03506
03507 HeapTupleSetHotUpdated(&oldtup);
03508
03509 HeapTupleSetHeapOnly(heaptup);
03510
03511 HeapTupleSetHeapOnly(newtup);
03512 }
03513 else
03514 {
03515
03516 HeapTupleClearHotUpdated(&oldtup);
03517 HeapTupleClearHeapOnly(heaptup);
03518 HeapTupleClearHeapOnly(newtup);
03519 }
03520
03521 RelationPutHeapTuple(relation, newbuf, heaptup);
03522
03523 if (!already_marked)
03524 {
03525
03526 oldtup.t_data->t_infomask &= ~(HEAP_XMAX_BITS | HEAP_MOVED);
03527 oldtup.t_data->t_infomask2 &= ~HEAP_KEYS_UPDATED;
03528
03529 Assert(TransactionIdIsValid(xmax_old_tuple));
03530 HeapTupleHeaderSetXmax(oldtup.t_data, xmax_old_tuple);
03531 oldtup.t_data->t_infomask |= infomask_old_tuple;
03532 oldtup.t_data->t_infomask2 |= infomask2_old_tuple;
03533 HeapTupleHeaderSetCmax(oldtup.t_data, cid, iscombo);
03534 }
03535
03536
03537 oldtup.t_data->t_ctid = heaptup->t_self;
03538
03539
03540 if (PageIsAllVisible(BufferGetPage(buffer)))
03541 {
03542 all_visible_cleared = true;
03543 PageClearAllVisible(BufferGetPage(buffer));
03544 visibilitymap_clear(relation, BufferGetBlockNumber(buffer),
03545 vmbuffer);
03546 }
03547 if (newbuf != buffer && PageIsAllVisible(BufferGetPage(newbuf)))
03548 {
03549 all_visible_cleared_new = true;
03550 PageClearAllVisible(BufferGetPage(newbuf));
03551 visibilitymap_clear(relation, BufferGetBlockNumber(newbuf),
03552 vmbuffer_new);
03553 }
03554
03555 if (newbuf != buffer)
03556 MarkBufferDirty(newbuf);
03557 MarkBufferDirty(buffer);
03558
03559
03560 if (RelationNeedsWAL(relation))
03561 {
03562 XLogRecPtr recptr = log_heap_update(relation, buffer,
03563 newbuf, &oldtup, heaptup,
03564 all_visible_cleared,
03565 all_visible_cleared_new);
03566
03567 if (newbuf != buffer)
03568 {
03569 PageSetLSN(BufferGetPage(newbuf), recptr);
03570 }
03571 PageSetLSN(BufferGetPage(buffer), recptr);
03572 }
03573
03574 END_CRIT_SECTION();
03575
03576 if (newbuf != buffer)
03577 LockBuffer(newbuf, BUFFER_LOCK_UNLOCK);
03578 LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
03579
03580
03581
03582
03583
03584
03585
03586
03587
03588 CacheInvalidateHeapTuple(relation, &oldtup, heaptup);
03589
03590
03591 if (newbuf != buffer)
03592 ReleaseBuffer(newbuf);
03593 ReleaseBuffer(buffer);
03594 if (BufferIsValid(vmbuffer_new))
03595 ReleaseBuffer(vmbuffer_new);
03596 if (BufferIsValid(vmbuffer))
03597 ReleaseBuffer(vmbuffer);
03598
03599
03600
03601
03602 if (have_tuple_lock)
03603 UnlockTupleTuplock(relation, &(oldtup.t_self), *lockmode);
03604
03605 pgstat_count_heap_update(relation, use_hot_update);
03606
03607
03608
03609
03610
03611 if (heaptup != newtup)
03612 {
03613 newtup->t_self = heaptup->t_self;
03614 heap_freetuple(heaptup);
03615 }
03616
03617 bms_free(hot_attrs);
03618 bms_free(key_attrs);
03619
03620 return HeapTupleMayBeUpdated;
03621 }
03622
03623
03624
03625
03626
03627 static bool
03628 heap_tuple_attr_equals(TupleDesc tupdesc, int attrnum,
03629 HeapTuple tup1, HeapTuple tup2)
03630 {
03631 Datum value1,
03632 value2;
03633 bool isnull1,
03634 isnull2;
03635 Form_pg_attribute att;
03636
03637
03638
03639
03640
03641
03642 if (attrnum == 0)
03643 return false;
03644
03645
03646
03647
03648
03649
03650 if (attrnum < 0)
03651 {
03652 if (attrnum != ObjectIdAttributeNumber &&
03653 attrnum != TableOidAttributeNumber)
03654 return false;
03655 }
03656
03657
03658
03659
03660
03661
03662
03663 value1 = heap_getattr(tup1, attrnum, tupdesc, &isnull1);
03664 value2 = heap_getattr(tup2, attrnum, tupdesc, &isnull2);
03665
03666
03667
03668
03669
03670 if (isnull1 != isnull2)
03671 return false;
03672
03673
03674
03675
03676 if (isnull1)
03677 return true;
03678
03679
03680
03681
03682
03683
03684
03685
03686
03687
03688 if (attrnum <= 0)
03689 {
03690
03691 return (DatumGetObjectId(value1) == DatumGetObjectId(value2));
03692 }
03693 else
03694 {
03695 Assert(attrnum <= tupdesc->natts);
03696 att = tupdesc->attrs[attrnum - 1];
03697 return datumIsEqual(value1, value2, att->attbyval, att->attlen);
03698 }
03699 }
03700
03701
03702
03703
03704
03705
03706
03707
03708
03709
03710
03711
03712
03713
03714
03715
03716
03717 static void
03718 HeapSatisfiesHOTandKeyUpdate(Relation relation,
03719 Bitmapset *hot_attrs, Bitmapset *key_attrs,
03720 bool *satisfies_hot, bool *satisfies_key,
03721 HeapTuple oldtup, HeapTuple newtup)
03722 {
03723 int next_hot_attnum;
03724 int next_key_attnum;
03725 bool hot_result = true;
03726 bool key_result = true;
03727 bool key_done = false;
03728 bool hot_done = false;
03729
03730 next_hot_attnum = bms_first_member(hot_attrs);
03731 if (next_hot_attnum == -1)
03732 hot_done = true;
03733 else
03734
03735 next_hot_attnum += FirstLowInvalidHeapAttributeNumber;
03736
03737 next_key_attnum = bms_first_member(key_attrs);
03738 if (next_key_attnum == -1)
03739 key_done = true;
03740 else
03741
03742 next_key_attnum += FirstLowInvalidHeapAttributeNumber;
03743
03744 for (;;)
03745 {
03746 int check_now;
03747 bool changed;
03748
03749
03750 if (key_done && hot_done)
03751 break;
03752
03753
03754 if (hot_done)
03755 check_now = next_key_attnum;
03756 if (key_done)
03757 check_now = next_hot_attnum;
03758 else
03759 check_now = Min(next_hot_attnum, next_key_attnum);
03760
03761 changed = !heap_tuple_attr_equals(RelationGetDescr(relation),
03762 check_now, oldtup, newtup);
03763 if (changed)
03764 {
03765 if (check_now == next_hot_attnum)
03766 hot_result = false;
03767 if (check_now == next_key_attnum)
03768 key_result = false;
03769 }
03770
03771
03772 if (!hot_result && !key_result)
03773 break;
03774
03775 if (check_now == next_hot_attnum)
03776 {
03777 next_hot_attnum = bms_first_member(hot_attrs);
03778 if (next_hot_attnum == -1)
03779 hot_done = true;
03780 else
03781
03782 next_hot_attnum += FirstLowInvalidHeapAttributeNumber;
03783 }
03784 if (check_now == next_key_attnum)
03785 {
03786 next_key_attnum = bms_first_member(key_attrs);
03787 if (next_key_attnum == -1)
03788 key_done = true;
03789 else
03790
03791 next_key_attnum += FirstLowInvalidHeapAttributeNumber;
03792 }
03793 }
03794
03795 *satisfies_hot = hot_result;
03796 *satisfies_key = key_result;
03797 }
03798
03799
03800
03801
03802
03803
03804
03805
03806
03807 void
03808 simple_heap_update(Relation relation, ItemPointer otid, HeapTuple tup)
03809 {
03810 HTSU_Result result;
03811 HeapUpdateFailureData hufd;
03812 LockTupleMode lockmode;
03813
03814 result = heap_update(relation, otid, tup,
03815 GetCurrentCommandId(true), InvalidSnapshot,
03816 true ,
03817 &hufd, &lockmode);
03818 switch (result)
03819 {
03820 case HeapTupleSelfUpdated:
03821
03822 elog(ERROR, "tuple already updated by self");
03823 break;
03824
03825 case HeapTupleMayBeUpdated:
03826
03827 break;
03828
03829 case HeapTupleUpdated:
03830 elog(ERROR, "tuple concurrently updated");
03831 break;
03832
03833 default:
03834 elog(ERROR, "unrecognized heap_update status: %u", result);
03835 break;
03836 }
03837 }
03838
03839
03840
03841
03842
03843 static MultiXactStatus
03844 get_mxact_status_for_lock(LockTupleMode mode, bool is_update)
03845 {
03846 MultiXactStatus retval;
03847
03848 if (is_update)
03849 retval = tupleLockExtraInfo[mode].updstatus;
03850 else
03851 retval = tupleLockExtraInfo[mode].lockstatus;
03852
03853 if (retval == -1)
03854 elog(ERROR, "invalid lock tuple mode %d/%s", mode,
03855 is_update ? "true" : "false");
03856
03857 return retval;
03858 }
03859
03860
03861
03862
03863
03864
03865
03866
03867
03868
03869
03870
03871
03872
03873
03874
03875
03876
03877
03878
03879
03880
03881
03882
03883
03884
03885
03886
03887
03888
03889
03890
03891
03892
03893
03894 HTSU_Result
03895 heap_lock_tuple(Relation relation, HeapTuple tuple,
03896 CommandId cid, LockTupleMode mode, bool nowait,
03897 bool follow_updates,
03898 Buffer *buffer, HeapUpdateFailureData *hufd)
03899 {
03900 HTSU_Result result;
03901 ItemPointer tid = &(tuple->t_self);
03902 ItemId lp;
03903 Page page;
03904 TransactionId xid,
03905 xmax;
03906 uint16 old_infomask,
03907 new_infomask,
03908 new_infomask2;
03909 bool have_tuple_lock = false;
03910
03911 *buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));
03912 LockBuffer(*buffer, BUFFER_LOCK_EXCLUSIVE);
03913
03914 page = BufferGetPage(*buffer);
03915 lp = PageGetItemId(page, ItemPointerGetOffsetNumber(tid));
03916 Assert(ItemIdIsNormal(lp));
03917
03918 tuple->t_data = (HeapTupleHeader) PageGetItem(page, lp);
03919 tuple->t_len = ItemIdGetLength(lp);
03920 tuple->t_tableOid = RelationGetRelid(relation);
03921
03922 l3:
03923 result = HeapTupleSatisfiesUpdate(tuple->t_data, cid, *buffer);
03924
03925 if (result == HeapTupleInvisible)
03926 {
03927 UnlockReleaseBuffer(*buffer);
03928 elog(ERROR, "attempted to lock invisible tuple");
03929 }
03930 else if (result == HeapTupleBeingUpdated)
03931 {
03932 TransactionId xwait;
03933 uint16 infomask;
03934 uint16 infomask2;
03935 bool require_sleep;
03936 ItemPointerData t_ctid;
03937
03938
03939 xwait = HeapTupleHeaderGetRawXmax(tuple->t_data);
03940 infomask = tuple->t_data->t_infomask;
03941 infomask2 = tuple->t_data->t_infomask2;
03942 ItemPointerCopy(&tuple->t_data->t_ctid, &t_ctid);
03943
03944 LockBuffer(*buffer, BUFFER_LOCK_UNLOCK);
03945
03946
03947
03948
03949
03950
03951
03952
03953 if (infomask & HEAP_XMAX_IS_MULTI)
03954 {
03955 int i;
03956 int nmembers;
03957 MultiXactMember *members;
03958
03959
03960
03961
03962
03963
03964 nmembers = GetMultiXactIdMembers(xwait, &members, false);
03965
03966 for (i = 0; i < nmembers; i++)
03967 {
03968 if (TransactionIdIsCurrentTransactionId(members[i].xid))
03969 {
03970 LockTupleMode membermode;
03971
03972 membermode = TUPLOCK_from_mxstatus(members[i].status);
03973
03974 if (membermode >= mode)
03975 {
03976 if (have_tuple_lock)
03977 UnlockTupleTuplock(relation, tid, mode);
03978
03979 pfree(members);
03980 return HeapTupleMayBeUpdated;
03981 }
03982 }
03983 }
03984
03985 pfree(members);
03986 }
03987
03988
03989
03990
03991
03992
03993
03994
03995
03996
03997 if (!have_tuple_lock)
03998 {
03999 if (nowait)
04000 {
04001 if (!ConditionalLockTupleTuplock(relation, tid, mode))
04002 ereport(ERROR,
04003 (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
04004 errmsg("could not obtain lock on row in relation \"%s\"",
04005 RelationGetRelationName(relation))));
04006 }
04007 else
04008 LockTupleTuplock(relation, tid, mode);
04009 have_tuple_lock = true;
04010 }
04011
04012
04013
04014
04015
04016
04017 require_sleep = true;
04018 if (mode == LockTupleKeyShare)
04019 {
04020
04021
04022
04023
04024
04025
04026
04027
04028
04029
04030
04031
04032
04033
04034
04035
04036
04037
04038
04039
04040
04041 if (!(infomask2 & HEAP_KEYS_UPDATED))
04042 {
04043 bool updated;
04044
04045 updated = !HEAP_XMAX_IS_LOCKED_ONLY(infomask);
04046
04047
04048
04049
04050
04051 if (follow_updates && updated)
04052 {
04053 HTSU_Result res;
04054
04055 res = heap_lock_updated_tuple(relation, tuple, &t_ctid,
04056 GetCurrentTransactionId(),
04057 mode);
04058 if (res != HeapTupleMayBeUpdated)
04059 {
04060 result = res;
04061
04062 LockBuffer(*buffer, BUFFER_LOCK_EXCLUSIVE);
04063 goto failed;
04064 }
04065 }
04066
04067 LockBuffer(*buffer, BUFFER_LOCK_EXCLUSIVE);
04068
04069
04070
04071
04072
04073
04074
04075 if (!HeapTupleHeaderIsOnlyLocked(tuple->t_data) &&
04076 ((tuple->t_data->t_infomask2 & HEAP_KEYS_UPDATED) ||
04077 !updated))
04078 goto l3;
04079
04080
04081 require_sleep = false;
04082
04083
04084
04085
04086
04087
04088
04089
04090 }
04091 }
04092 else if (mode == LockTupleShare)
04093 {
04094
04095
04096
04097
04098 if (HEAP_XMAX_IS_LOCKED_ONLY(infomask) &&
04099 !HEAP_XMAX_IS_EXCL_LOCKED(infomask))
04100 {
04101 LockBuffer(*buffer, BUFFER_LOCK_EXCLUSIVE);
04102
04103
04104
04105
04106
04107 if (!HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_data->t_infomask) ||
04108 HEAP_XMAX_IS_EXCL_LOCKED(tuple->t_data->t_infomask))
04109 goto l3;
04110 require_sleep = false;
04111 }
04112 }
04113 else if (mode == LockTupleNoKeyExclusive)
04114 {
04115
04116
04117
04118
04119
04120
04121
04122
04123 if (infomask & HEAP_XMAX_IS_MULTI)
04124 {
04125 int nmembers;
04126 MultiXactMember *members;
04127
04128
04129
04130
04131
04132
04133 nmembers = GetMultiXactIdMembers(xwait, &members, false);
04134
04135 if (nmembers <= 0)
04136 {
04137
04138
04139
04140
04141 require_sleep = false;
04142 }
04143 else
04144 {
04145 int i;
04146 bool allowed = true;
04147
04148 for (i = 0; i < nmembers; i++)
04149 {
04150 if (members[i].status != MultiXactStatusForKeyShare)
04151 {
04152 allowed = false;
04153 break;
04154 }
04155 }
04156 if (allowed)
04157 {
04158
04159
04160
04161
04162 LockBuffer(*buffer, BUFFER_LOCK_EXCLUSIVE);
04163 if (!(tuple->t_data->t_infomask & HEAP_XMAX_IS_MULTI) ||
04164 !TransactionIdEquals(HeapTupleHeaderGetRawXmax(tuple->t_data),
04165 xwait))
04166 {
04167 pfree(members);
04168 goto l3;
04169 }
04170
04171 require_sleep = false;
04172 }
04173
04174 pfree(members);
04175 }
04176 }
04177 else if (HEAP_XMAX_IS_KEYSHR_LOCKED(infomask))
04178 {
04179 LockBuffer(*buffer, BUFFER_LOCK_EXCLUSIVE);
04180
04181
04182 if ((tuple->t_data->t_infomask & HEAP_XMAX_IS_MULTI) ||
04183 !TransactionIdEquals(HeapTupleHeaderGetRawXmax(tuple->t_data),
04184 xwait))
04185 goto l3;
04186
04187 require_sleep = false;
04188 }
04189 }
04190
04191
04192
04193
04194
04195
04196
04197 if (require_sleep)
04198 {
04199 if (infomask & HEAP_XMAX_IS_MULTI)
04200 {
04201 MultiXactStatus status = get_mxact_status_for_lock(mode, false);
04202
04203
04204 if (status >= MultiXactStatusNoKeyUpdate)
04205 elog(ERROR, "invalid lock mode in heap_lock_tuple");
04206
04207
04208 if (nowait)
04209 {
04210 if (!ConditionalMultiXactIdWait((MultiXactId) xwait,
04211 status, NULL, infomask))
04212 ereport(ERROR,
04213 (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
04214 errmsg("could not obtain lock on row in relation \"%s\"",
04215 RelationGetRelationName(relation))));
04216 }
04217 else
04218 MultiXactIdWait((MultiXactId) xwait, status, NULL, infomask);
04219
04220
04221 if (follow_updates &&
04222 !HEAP_XMAX_IS_LOCKED_ONLY(infomask))
04223 {
04224 HTSU_Result res;
04225
04226 res = heap_lock_updated_tuple(relation, tuple, &t_ctid,
04227 GetCurrentTransactionId(),
04228 mode);
04229 if (res != HeapTupleMayBeUpdated)
04230 {
04231 result = res;
04232
04233 LockBuffer(*buffer, BUFFER_LOCK_EXCLUSIVE);
04234 goto failed;
04235 }
04236 }
04237
04238 LockBuffer(*buffer, BUFFER_LOCK_EXCLUSIVE);
04239
04240
04241
04242
04243
04244
04245 if (!(tuple->t_data->t_infomask & HEAP_XMAX_IS_MULTI) ||
04246 !TransactionIdEquals(HeapTupleHeaderGetRawXmax(tuple->t_data),
04247 xwait))
04248 goto l3;
04249
04250
04251
04252
04253
04254
04255
04256
04257
04258
04259 }
04260 else
04261 {
04262
04263 if (nowait)
04264 {
04265 if (!ConditionalXactLockTableWait(xwait))
04266 ereport(ERROR,
04267 (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
04268 errmsg("could not obtain lock on row in relation \"%s\"",
04269 RelationGetRelationName(relation))));
04270 }
04271 else
04272 XactLockTableWait(xwait);
04273
04274
04275 if (follow_updates &&
04276 !HEAP_XMAX_IS_LOCKED_ONLY(infomask))
04277 {
04278 HTSU_Result res;
04279
04280 res = heap_lock_updated_tuple(relation, tuple, &t_ctid,
04281 GetCurrentTransactionId(),
04282 mode);
04283 if (res != HeapTupleMayBeUpdated)
04284 {
04285 result = res;
04286
04287 LockBuffer(*buffer, BUFFER_LOCK_EXCLUSIVE);
04288 goto failed;
04289 }
04290 }
04291
04292 LockBuffer(*buffer, BUFFER_LOCK_EXCLUSIVE);
04293
04294
04295
04296
04297
04298
04299 if ((tuple->t_data->t_infomask & HEAP_XMAX_IS_MULTI) ||
04300 !TransactionIdEquals(HeapTupleHeaderGetRawXmax(tuple->t_data),
04301 xwait))
04302 goto l3;
04303
04304
04305
04306
04307
04308
04309
04310 UpdateXmaxHintBits(tuple->t_data, *buffer, xwait);
04311 }
04312 }
04313
04314
04315
04316
04317
04318
04319
04320
04321 if (!require_sleep ||
04322 (tuple->t_data->t_infomask & HEAP_XMAX_INVALID) ||
04323 HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_data->t_infomask) ||
04324 HeapTupleHeaderIsOnlyLocked(tuple->t_data))
04325 result = HeapTupleMayBeUpdated;
04326 else
04327 result = HeapTupleUpdated;
04328 }
04329
04330 failed:
04331 if (result != HeapTupleMayBeUpdated)
04332 {
04333 Assert(result == HeapTupleSelfUpdated || result == HeapTupleUpdated);
04334 Assert(!(tuple->t_data->t_infomask & HEAP_XMAX_INVALID));
04335 hufd->ctid = tuple->t_data->t_ctid;
04336 hufd->xmax = HeapTupleHeaderGetUpdateXid(tuple->t_data);
04337 if (result == HeapTupleSelfUpdated)
04338 hufd->cmax = HeapTupleHeaderGetCmax(tuple->t_data);
04339 else
04340 hufd->cmax = 0;
04341 LockBuffer(*buffer, BUFFER_LOCK_UNLOCK);
04342 if (have_tuple_lock)
04343 UnlockTupleTuplock(relation, tid, mode);
04344 return result;
04345 }
04346
04347 xmax = HeapTupleHeaderGetRawXmax(tuple->t_data);
04348 old_infomask = tuple->t_data->t_infomask;
04349
04350
04351
04352
04353
04354
04355
04356
04357
04358
04359
04360
04361 if (!(old_infomask & (HEAP_XMAX_INVALID |
04362 HEAP_XMAX_COMMITTED |
04363 HEAP_XMAX_IS_MULTI)) &&
04364 (mode == LockTupleKeyShare ?
04365 (HEAP_XMAX_IS_KEYSHR_LOCKED(old_infomask) ||
04366 HEAP_XMAX_IS_SHR_LOCKED(old_infomask) ||
04367 HEAP_XMAX_IS_EXCL_LOCKED(old_infomask)) :
04368 mode == LockTupleShare ?
04369 (HEAP_XMAX_IS_SHR_LOCKED(old_infomask) ||
04370 HEAP_XMAX_IS_EXCL_LOCKED(old_infomask)) :
04371 (HEAP_XMAX_IS_EXCL_LOCKED(old_infomask))) &&
04372 TransactionIdIsCurrentTransactionId(xmax))
04373 {
04374 LockBuffer(*buffer, BUFFER_LOCK_UNLOCK);
04375
04376 if (have_tuple_lock)
04377 UnlockTupleTuplock(relation, tid, mode);
04378 return HeapTupleMayBeUpdated;
04379 }
04380
04381
04382
04383
04384
04385
04386
04387
04388
04389
04390 MultiXactIdSetOldestMember();
04391
04392
04393
04394
04395
04396
04397 compute_new_xmax_infomask(xmax, old_infomask, tuple->t_data->t_infomask2,
04398 GetCurrentTransactionId(), mode, false,
04399 &xid, &new_infomask, &new_infomask2);
04400
04401 START_CRIT_SECTION();
04402
04403
04404
04405
04406
04407
04408
04409
04410
04411
04412
04413 tuple->t_data->t_infomask &= ~HEAP_XMAX_BITS;
04414 tuple->t_data->t_infomask2 &= ~HEAP_KEYS_UPDATED;
04415 tuple->t_data->t_infomask |= new_infomask;
04416 tuple->t_data->t_infomask2 |= new_infomask2;
04417 if (HEAP_XMAX_IS_LOCKED_ONLY(new_infomask))
04418 HeapTupleHeaderClearHotUpdated(tuple->t_data);
04419 HeapTupleHeaderSetXmax(tuple->t_data, xid);
04420
04421
04422
04423
04424
04425
04426
04427
04428 if (HEAP_XMAX_IS_LOCKED_ONLY(new_infomask))
04429 tuple->t_data->t_ctid = *tid;
04430
04431 MarkBufferDirty(*buffer);
04432
04433
04434
04435
04436
04437
04438
04439
04440
04441
04442
04443
04444
04445 if (RelationNeedsWAL(relation))
04446 {
04447 xl_heap_lock xlrec;
04448 XLogRecPtr recptr;
04449 XLogRecData rdata[2];
04450
04451 xlrec.target.node = relation->rd_node;
04452 xlrec.target.tid = tuple->t_self;
04453 xlrec.locking_xid = xid;
04454 xlrec.infobits_set = compute_infobits(new_infomask,
04455 tuple->t_data->t_infomask2);
04456 rdata[0].data = (char *) &xlrec;
04457 rdata[0].len = SizeOfHeapLock;
04458 rdata[0].buffer = InvalidBuffer;
04459 rdata[0].next = &(rdata[1]);
04460
04461 rdata[1].data = NULL;
04462 rdata[1].len = 0;
04463 rdata[1].buffer = *buffer;
04464 rdata[1].buffer_std = true;
04465 rdata[1].next = NULL;
04466
04467 recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_LOCK, rdata);
04468
04469 PageSetLSN(page, recptr);
04470 }
04471
04472 END_CRIT_SECTION();
04473
04474 LockBuffer(*buffer, BUFFER_LOCK_UNLOCK);
04475
04476
04477
04478
04479
04480
04481
04482
04483
04484
04485 if (have_tuple_lock)
04486 UnlockTupleTuplock(relation, tid, mode);
04487
04488 return HeapTupleMayBeUpdated;
04489 }
04490
04491
04492
04493
04494
04495
04496
04497
04498
04499
04500
04501
04502
04503
04504
04505
04506
04507
04508
04509
04510 static void
04511 compute_new_xmax_infomask(TransactionId xmax, uint16 old_infomask,
04512 uint16 old_infomask2, TransactionId add_to_xmax,
04513 LockTupleMode mode, bool is_update,
04514 TransactionId *result_xmax, uint16 *result_infomask,
04515 uint16 *result_infomask2)
04516 {
04517 TransactionId new_xmax;
04518 uint16 new_infomask,
04519 new_infomask2;
04520
04521 l5:
04522 new_infomask = 0;
04523 new_infomask2 = 0;
04524 if (old_infomask & HEAP_XMAX_INVALID)
04525 {
04526
04527
04528
04529 if (is_update)
04530 {
04531 new_xmax = add_to_xmax;
04532 if (mode == LockTupleExclusive)
04533 new_infomask2 |= HEAP_KEYS_UPDATED;
04534 }
04535 else
04536 {
04537 new_infomask |= HEAP_XMAX_LOCK_ONLY;
04538 switch (mode)
04539 {
04540 case LockTupleKeyShare:
04541 new_xmax = add_to_xmax;
04542 new_infomask |= HEAP_XMAX_KEYSHR_LOCK;
04543 break;
04544 case LockTupleShare:
04545 new_xmax = add_to_xmax;
04546 new_infomask |= HEAP_XMAX_SHR_LOCK;
04547 break;
04548 case LockTupleNoKeyExclusive:
04549 new_xmax = add_to_xmax;
04550 new_infomask |= HEAP_XMAX_EXCL_LOCK;
04551 break;
04552 case LockTupleExclusive:
04553 new_xmax = add_to_xmax;
04554 new_infomask |= HEAP_XMAX_EXCL_LOCK;
04555 new_infomask2 |= HEAP_KEYS_UPDATED;
04556 break;
04557 default:
04558 new_xmax = InvalidTransactionId;
04559 elog(ERROR, "invalid lock mode");
04560 }
04561 }
04562 }
04563 else if (old_infomask & HEAP_XMAX_IS_MULTI)
04564 {
04565 MultiXactStatus new_status;
04566
04567
04568
04569
04570
04571 Assert(!(old_infomask & HEAP_XMAX_COMMITTED));
04572
04573
04574
04575
04576
04577
04578
04579
04580 if (!(old_infomask & HEAP_LOCK_MASK) &&
04581 HEAP_XMAX_IS_LOCKED_ONLY(old_infomask))
04582 {
04583 old_infomask &= ~HEAP_XMAX_IS_MULTI;
04584 old_infomask |= HEAP_XMAX_INVALID;
04585 goto l5;
04586 }
04587
04588
04589
04590
04591
04592
04593
04594
04595
04596
04597
04598
04599 if (!MultiXactIdIsRunning(xmax))
04600 {
04601 if (HEAP_XMAX_IS_LOCKED_ONLY(old_infomask) ||
04602 TransactionIdDidAbort(MultiXactIdGetUpdateXid(xmax,
04603 old_infomask)))
04604 {
04605
04606
04607
04608
04609 old_infomask &= ~HEAP_XMAX_IS_MULTI;
04610 old_infomask |= HEAP_XMAX_INVALID;
04611 goto l5;
04612 }
04613 }
04614
04615 new_status = get_mxact_status_for_lock(mode, is_update);
04616
04617 new_xmax = MultiXactIdExpand((MultiXactId) xmax, add_to_xmax,
04618 new_status);
04619 GetMultiXactIdHintBits(new_xmax, &new_infomask, &new_infomask2);
04620 }
04621 else if (old_infomask & HEAP_XMAX_COMMITTED)
04622 {
04623
04624
04625
04626
04627 MultiXactStatus status;
04628 MultiXactStatus new_status;
04629
04630 if (old_infomask2 & HEAP_KEYS_UPDATED)
04631 status = MultiXactStatusUpdate;
04632 else
04633 status = MultiXactStatusNoKeyUpdate;
04634
04635 new_status = get_mxact_status_for_lock(mode, is_update);
04636
04637
04638
04639
04640
04641 new_xmax = MultiXactIdCreate(xmax, status, add_to_xmax, new_status);
04642 GetMultiXactIdHintBits(new_xmax, &new_infomask, &new_infomask2);
04643 }
04644 else if (TransactionIdIsInProgress(xmax))
04645 {
04646
04647
04648
04649
04650
04651 MultiXactStatus status;
04652 MultiXactStatus new_status;
04653
04654 if (HEAP_XMAX_IS_LOCKED_ONLY(old_infomask))
04655 {
04656 if (HEAP_XMAX_IS_KEYSHR_LOCKED(old_infomask))
04657 status = MultiXactStatusForKeyShare;
04658 else if (HEAP_XMAX_IS_SHR_LOCKED(old_infomask))
04659 status = MultiXactStatusForShare;
04660 else if (HEAP_XMAX_IS_EXCL_LOCKED(old_infomask))
04661 {
04662 if (old_infomask2 & HEAP_KEYS_UPDATED)
04663 status = MultiXactStatusForUpdate;
04664 else
04665 status = MultiXactStatusForNoKeyUpdate;
04666 }
04667 else
04668 {
04669
04670
04671
04672
04673
04674
04675 elog(WARNING, "LOCK_ONLY found for Xid in progress %u", xmax);
04676 old_infomask |= HEAP_XMAX_INVALID;
04677 old_infomask &= ~HEAP_XMAX_LOCK_ONLY;
04678 goto l5;
04679 }
04680 }
04681 else
04682 {
04683
04684 if (old_infomask2 & HEAP_KEYS_UPDATED)
04685 status = MultiXactStatusUpdate;
04686 else
04687 status = MultiXactStatusNoKeyUpdate;
04688 }
04689
04690 new_status = get_mxact_status_for_lock(mode, is_update);
04691
04692
04693
04694
04695
04696
04697 if (xmax == add_to_xmax)
04698 {
04699 LockTupleMode old_mode = TUPLOCK_from_mxstatus(status);
04700 bool old_isupd = ISUPDATE_from_mxstatus(status);
04701
04702
04703
04704
04705
04706
04707
04708 if ((mode >= old_mode) && (is_update || !old_isupd))
04709 {
04710
04711
04712
04713
04714
04715
04716
04717 old_infomask |= HEAP_XMAX_INVALID;
04718 goto l5;
04719 }
04720 }
04721 new_xmax = MultiXactIdCreate(xmax, status, add_to_xmax, new_status);
04722 GetMultiXactIdHintBits(new_xmax, &new_infomask, &new_infomask2);
04723 }
04724 else if (!HEAP_XMAX_IS_LOCKED_ONLY(old_infomask) &&
04725 TransactionIdDidCommit(xmax))
04726 {
04727
04728
04729
04730
04731 MultiXactStatus status;
04732 MultiXactStatus new_status;
04733
04734 if (old_infomask2 & HEAP_KEYS_UPDATED)
04735 status = MultiXactStatusUpdate;
04736 else
04737 status = MultiXactStatusNoKeyUpdate;
04738
04739 new_status = get_mxact_status_for_lock(mode, is_update);
04740
04741
04742
04743
04744
04745 new_xmax = MultiXactIdCreate(xmax, status, add_to_xmax, new_status);
04746 GetMultiXactIdHintBits(new_xmax, &new_infomask, &new_infomask2);
04747 }
04748 else
04749 {
04750
04751
04752
04753
04754
04755
04756 old_infomask |= HEAP_XMAX_INVALID;
04757 goto l5;
04758 }
04759
04760 *result_infomask = new_infomask;
04761 *result_infomask2 = new_infomask2;
04762 *result_xmax = new_xmax;
04763 }
04764
04765
04766
04767
04768
04769
04770
04771
04772
04773 static HTSU_Result
04774 heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
04775 LockTupleMode mode)
04776 {
04777 ItemPointerData tupid;
04778 HeapTupleData mytup;
04779 Buffer buf;
04780 uint16 new_infomask,
04781 new_infomask2,
04782 old_infomask;
04783 TransactionId xmax,
04784 new_xmax;
04785
04786 ItemPointerCopy(tid, &tupid);
04787
04788 for (;;)
04789 {
04790 new_infomask = 0;
04791 new_xmax = InvalidTransactionId;
04792 ItemPointerCopy(&tupid, &(mytup.t_self));
04793
04794 if (!heap_fetch(rel, SnapshotAny, &mytup, &buf, false, NULL))
04795 elog(ERROR, "unable to fetch updated version of tuple");
04796
04797 l4:
04798 CHECK_FOR_INTERRUPTS();
04799 LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
04800
04801 old_infomask = mytup.t_data->t_infomask;
04802 xmax = HeapTupleHeaderGetRawXmax(mytup.t_data);
04803
04804
04805
04806
04807
04808
04809
04810
04811 if (!(old_infomask & HEAP_XMAX_INVALID) &&
04812 (mytup.t_data->t_infomask2 & HEAP_KEYS_UPDATED))
04813 {
04814 TransactionId update_xid;
04815
04816
04817
04818
04819
04820
04821 update_xid = HeapTupleHeaderGetUpdateXid(mytup.t_data);
04822 if (TransactionIdIsCurrentTransactionId(update_xid))
04823 {
04824 UnlockReleaseBuffer(buf);
04825 return HeapTupleSelfUpdated;
04826 }
04827 else if (TransactionIdIsInProgress(update_xid))
04828 {
04829 LockBuffer(buf, BUFFER_LOCK_UNLOCK);
04830
04831 XactLockTableWait(update_xid);
04832 goto l4;
04833 }
04834 else if (TransactionIdDidAbort(update_xid))
04835 ;
04836 else if (TransactionIdDidCommit(update_xid))
04837 {
04838 UnlockReleaseBuffer(buf);
04839 return HeapTupleUpdated;
04840 }
04841 }
04842
04843
04844 compute_new_xmax_infomask(xmax, old_infomask, mytup.t_data->t_infomask2,
04845 xid, mode, false,
04846 &new_xmax, &new_infomask, &new_infomask2);
04847
04848 START_CRIT_SECTION();
04849
04850
04851 HeapTupleHeaderSetXmax(mytup.t_data, new_xmax);
04852 mytup.t_data->t_infomask &= ~HEAP_XMAX_BITS;
04853 mytup.t_data->t_infomask2 &= ~HEAP_KEYS_UPDATED;
04854 mytup.t_data->t_infomask |= new_infomask;
04855 mytup.t_data->t_infomask2 |= new_infomask2;
04856
04857 MarkBufferDirty(buf);
04858
04859
04860 if (RelationNeedsWAL(rel))
04861 {
04862 xl_heap_lock_updated xlrec;
04863 XLogRecPtr recptr;
04864 XLogRecData rdata[2];
04865 Page page = BufferGetPage(buf);
04866
04867 xlrec.target.node = rel->rd_node;
04868 xlrec.target.tid = mytup.t_self;
04869 xlrec.xmax = new_xmax;
04870 xlrec.infobits_set = compute_infobits(new_infomask, new_infomask2);
04871
04872 rdata[0].data = (char *) &xlrec;
04873 rdata[0].len = SizeOfHeapLockUpdated;
04874 rdata[0].buffer = InvalidBuffer;
04875 rdata[0].next = &(rdata[1]);
04876
04877 rdata[1].data = NULL;
04878 rdata[1].len = 0;
04879 rdata[1].buffer = buf;
04880 rdata[1].buffer_std = true;
04881 rdata[1].next = NULL;
04882
04883 recptr = XLogInsert(RM_HEAP2_ID, XLOG_HEAP2_LOCK_UPDATED, rdata);
04884
04885 PageSetLSN(page, recptr);
04886 }
04887
04888 END_CRIT_SECTION();
04889
04890
04891 if (mytup.t_data->t_infomask & HEAP_XMAX_INVALID ||
04892 ItemPointerEquals(&mytup.t_self, &mytup.t_data->t_ctid) ||
04893 HeapTupleHeaderIsOnlyLocked(mytup.t_data))
04894 {
04895 UnlockReleaseBuffer(buf);
04896 return HeapTupleMayBeUpdated;
04897 }
04898
04899
04900 ItemPointerCopy(&(mytup.t_data->t_ctid), &tupid);
04901 UnlockReleaseBuffer(buf);
04902 }
04903 }
04904
04905
04906
04907
04908
04909
04910
04911
04912
04913
04914
04915
04916
04917
04918
04919
04920
04921
04922
04923
04924
04925
04926
04927 static HTSU_Result
04928 heap_lock_updated_tuple(Relation rel, HeapTuple tuple, ItemPointer ctid,
04929 TransactionId xid, LockTupleMode mode)
04930 {
04931 if (!ItemPointerEquals(&tuple->t_self, ctid))
04932 {
04933
04934
04935
04936
04937
04938
04939
04940
04941
04942 MultiXactIdSetOldestMember();
04943
04944 return heap_lock_updated_tuple_rec(rel, ctid, xid, mode);
04945 }
04946
04947
04948 return HeapTupleMayBeUpdated;
04949 }
04950
04951
04952
04953
04954
04955
04956
04957
04958
04959
04960
04961
04962
04963
04964
04965
04966
04967 void
04968 heap_inplace_update(Relation relation, HeapTuple tuple)
04969 {
04970 Buffer buffer;
04971 Page page;
04972 OffsetNumber offnum;
04973 ItemId lp = NULL;
04974 HeapTupleHeader htup;
04975 uint32 oldlen;
04976 uint32 newlen;
04977
04978 buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(&(tuple->t_self)));
04979 LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
04980 page = (Page) BufferGetPage(buffer);
04981
04982 offnum = ItemPointerGetOffsetNumber(&(tuple->t_self));
04983 if (PageGetMaxOffsetNumber(page) >= offnum)
04984 lp = PageGetItemId(page, offnum);
04985
04986 if (PageGetMaxOffsetNumber(page) < offnum || !ItemIdIsNormal(lp))
04987 elog(ERROR, "heap_inplace_update: invalid lp");
04988
04989 htup = (HeapTupleHeader) PageGetItem(page, lp);
04990
04991 oldlen = ItemIdGetLength(lp) - htup->t_hoff;
04992 newlen = tuple->t_len - tuple->t_data->t_hoff;
04993 if (oldlen != newlen || htup->t_hoff != tuple->t_data->t_hoff)
04994 elog(ERROR, "heap_inplace_update: wrong tuple length");
04995
04996
04997 START_CRIT_SECTION();
04998
04999 memcpy((char *) htup + htup->t_hoff,
05000 (char *) tuple->t_data + tuple->t_data->t_hoff,
05001 newlen);
05002
05003 MarkBufferDirty(buffer);
05004
05005
05006 if (RelationNeedsWAL(relation))
05007 {
05008 xl_heap_inplace xlrec;
05009 XLogRecPtr recptr;
05010 XLogRecData rdata[2];
05011
05012 xlrec.target.node = relation->rd_node;
05013 xlrec.target.tid = tuple->t_self;
05014
05015 rdata[0].data = (char *) &xlrec;
05016 rdata[0].len = SizeOfHeapInplace;
05017 rdata[0].buffer = InvalidBuffer;
05018 rdata[0].next = &(rdata[1]);
05019
05020 rdata[1].data = (char *) htup + htup->t_hoff;
05021 rdata[1].len = newlen;
05022 rdata[1].buffer = buffer;
05023 rdata[1].buffer_std = true;
05024 rdata[1].next = NULL;
05025
05026 recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_INPLACE, rdata);
05027
05028 PageSetLSN(page, recptr);
05029 }
05030
05031 END_CRIT_SECTION();
05032
05033 UnlockReleaseBuffer(buffer);
05034
05035
05036
05037
05038
05039
05040
05041 if (!IsBootstrapProcessingMode())
05042 CacheInvalidateHeapTuple(relation, tuple, NULL);
05043 }
05044
05045
05046
05047
05048
05049
05050
05051
05052
05053
05054
05055
05056
05057
05058
05059
05060
05061
05062
05063
05064
05065
05066
05067
05068
05069
05070
05071
05072
05073
05074
05075
05076
05077
05078
05079
05080
05081
05082
05083 bool
05084 heap_freeze_tuple(HeapTupleHeader tuple, TransactionId cutoff_xid,
05085 MultiXactId cutoff_multi)
05086 {
05087 bool changed = false;
05088 TransactionId xid;
05089
05090 xid = HeapTupleHeaderGetXmin(tuple);
05091 if (TransactionIdIsNormal(xid) &&
05092 TransactionIdPrecedes(xid, cutoff_xid))
05093 {
05094 HeapTupleHeaderSetXmin(tuple, FrozenTransactionId);
05095
05096
05097
05098
05099
05100 Assert(!(tuple->t_infomask & HEAP_XMIN_INVALID));
05101 tuple->t_infomask |= HEAP_XMIN_COMMITTED;
05102 changed = true;
05103 }
05104
05105
05106
05107
05108
05109
05110 xid = HeapTupleHeaderGetRawXmax(tuple);
05111 if ((tuple->t_infomask & HEAP_XMAX_IS_MULTI) ?
05112 (MultiXactIdIsValid(xid) &&
05113 MultiXactIdPrecedes(xid, cutoff_multi)) :
05114 (TransactionIdIsNormal(xid) &&
05115 TransactionIdPrecedes(xid, cutoff_xid)))
05116 {
05117 HeapTupleHeaderSetXmax(tuple, InvalidTransactionId);
05118
05119
05120
05121
05122
05123
05124 tuple->t_infomask &= ~HEAP_XMAX_BITS;
05125 tuple->t_infomask |= HEAP_XMAX_INVALID;
05126 HeapTupleHeaderClearHotUpdated(tuple);
05127 tuple->t_infomask2 &= ~HEAP_KEYS_UPDATED;
05128 changed = true;
05129 }
05130
05131
05132
05133
05134
05135 if (tuple->t_infomask & HEAP_MOVED)
05136 {
05137 xid = HeapTupleHeaderGetXvac(tuple);
05138 if (TransactionIdIsNormal(xid) &&
05139 TransactionIdPrecedes(xid, cutoff_xid))
05140 {
05141
05142
05143
05144
05145
05146 if (tuple->t_infomask & HEAP_MOVED_OFF)
05147 HeapTupleHeaderSetXvac(tuple, InvalidTransactionId);
05148 else
05149 HeapTupleHeaderSetXvac(tuple, FrozenTransactionId);
05150
05151
05152
05153
05154
05155 Assert(!(tuple->t_infomask & HEAP_XMIN_INVALID));
05156 tuple->t_infomask |= HEAP_XMIN_COMMITTED;
05157 changed = true;
05158 }
05159 }
05160
05161 return changed;
05162 }
05163
05164
05165
05166
05167
05168
05169
05170
05171 static void
05172 GetMultiXactIdHintBits(MultiXactId multi, uint16 *new_infomask,
05173 uint16 *new_infomask2)
05174 {
05175 int nmembers;
05176 MultiXactMember *members;
05177 int i;
05178 uint16 bits = HEAP_XMAX_IS_MULTI;
05179 uint16 bits2 = 0;
05180 bool has_update = false;
05181 LockTupleMode strongest = LockTupleKeyShare;
05182
05183
05184
05185
05186
05187 nmembers = GetMultiXactIdMembers(multi, &members, false);
05188
05189 for (i = 0; i < nmembers; i++)
05190 {
05191 LockTupleMode mode;
05192
05193
05194
05195
05196
05197 mode = TUPLOCK_from_mxstatus(members[i].status);
05198 if (mode > strongest)
05199 strongest = mode;
05200
05201
05202 switch (members[i].status)
05203 {
05204 case MultiXactStatusForKeyShare:
05205 case MultiXactStatusForShare:
05206 case MultiXactStatusForNoKeyUpdate:
05207 break;
05208
05209 case MultiXactStatusForUpdate:
05210 bits2 |= HEAP_KEYS_UPDATED;
05211 break;
05212
05213 case MultiXactStatusNoKeyUpdate:
05214 has_update = true;
05215 break;
05216
05217 case MultiXactStatusUpdate:
05218 bits2 |= HEAP_KEYS_UPDATED;
05219 has_update = true;
05220 break;
05221 }
05222 }
05223
05224 if (strongest == LockTupleExclusive ||
05225 strongest == LockTupleNoKeyExclusive)
05226 bits |= HEAP_XMAX_EXCL_LOCK;
05227 else if (strongest == LockTupleShare)
05228 bits |= HEAP_XMAX_SHR_LOCK;
05229 else if (strongest == LockTupleKeyShare)
05230 bits |= HEAP_XMAX_KEYSHR_LOCK;
05231
05232 if (!has_update)
05233 bits |= HEAP_XMAX_LOCK_ONLY;
05234
05235 if (nmembers > 0)
05236 pfree(members);
05237
05238 *new_infomask = bits;
05239 *new_infomask2 = bits2;
05240 }
05241
05242
05243
05244
05245
05246
05247
05248
05249 static TransactionId
05250 MultiXactIdGetUpdateXid(TransactionId xmax, uint16 t_infomask)
05251 {
05252 TransactionId update_xact = InvalidTransactionId;
05253 MultiXactMember *members;
05254 int nmembers;
05255
05256 Assert(!(t_infomask & HEAP_XMAX_LOCK_ONLY));
05257 Assert(t_infomask & HEAP_XMAX_IS_MULTI);
05258
05259
05260
05261
05262
05263 nmembers = GetMultiXactIdMembers(xmax, &members, false);
05264
05265 if (nmembers > 0)
05266 {
05267 int i;
05268
05269 for (i = 0; i < nmembers; i++)
05270 {
05271
05272 if (members[i].status == MultiXactStatusForKeyShare ||
05273 members[i].status == MultiXactStatusForShare ||
05274 members[i].status == MultiXactStatusForNoKeyUpdate ||
05275 members[i].status == MultiXactStatusForUpdate)
05276 continue;
05277
05278
05279 if (TransactionIdDidAbort(members[i].xid))
05280 continue;
05281
05282 Assert(update_xact == InvalidTransactionId);
05283 Assert(members[i].status == MultiXactStatusNoKeyUpdate ||
05284 members[i].status == MultiXactStatusUpdate);
05285 update_xact = members[i].xid;
05286 #ifndef USE_ASSERT_CHECKING
05287
05288
05289
05290
05291 break;
05292 #endif
05293 }
05294
05295 pfree(members);
05296 }
05297
05298 return update_xact;
05299 }
05300
05301
05302
05303
05304
05305
05306
05307
05308 TransactionId
05309 HeapTupleGetUpdateXid(HeapTupleHeader tuple)
05310 {
05311 return MultiXactIdGetUpdateXid(HeapTupleHeaderGetRawXmax(tuple),
05312 tuple->t_infomask);
05313 }
05314
05315
05316
05317
05318
05319
05320
05321
05322
05323
05324
05325
05326
05327
05328
05329
05330
05331
05332
05333
05334 static bool
05335 Do_MultiXactIdWait(MultiXactId multi, MultiXactStatus status,
05336 int *remaining, uint16 infomask, bool nowait)
05337 {
05338 bool allow_old;
05339 bool result = true;
05340 MultiXactMember *members;
05341 int nmembers;
05342 int remain = 0;
05343
05344 allow_old = !(infomask & HEAP_LOCK_MASK) && HEAP_XMAX_IS_LOCKED_ONLY(infomask);
05345 nmembers = GetMultiXactIdMembers(multi, &members, allow_old);
05346
05347 if (nmembers >= 0)
05348 {
05349 int i;
05350
05351 for (i = 0; i < nmembers; i++)
05352 {
05353 TransactionId memxid = members[i].xid;
05354 MultiXactStatus memstatus = members[i].status;
05355
05356 if (TransactionIdIsCurrentTransactionId(memxid))
05357 {
05358 remain++;
05359 continue;
05360 }
05361
05362 if (!DoLockModesConflict(LOCKMODE_from_mxstatus(memstatus),
05363 LOCKMODE_from_mxstatus(status)))
05364 {
05365 if (remaining && TransactionIdIsInProgress(memxid))
05366 remain++;
05367 continue;
05368 }
05369
05370
05371
05372
05373
05374 if (nowait)
05375 {
05376 result = ConditionalXactLockTableWait(memxid);
05377 if (!result)
05378 break;
05379 }
05380 else
05381 XactLockTableWait(memxid);
05382 }
05383
05384 pfree(members);
05385 }
05386
05387 if (remaining)
05388 *remaining = remain;
05389
05390 return result;
05391 }
05392
05393
05394
05395
05396
05397
05398
05399
05400
05401
05402
05403
05404 static void
05405 MultiXactIdWait(MultiXactId multi, MultiXactStatus status,
05406 int *remaining, uint16 infomask)
05407 {
05408 Do_MultiXactIdWait(multi, status, remaining, infomask, false);
05409 }
05410
05411
05412
05413
05414
05415
05416
05417
05418
05419
05420
05421
05422
05423
05424 static bool
05425 ConditionalMultiXactIdWait(MultiXactId multi, MultiXactStatus status,
05426 int *remaining, uint16 infomask)
05427 {
05428 return Do_MultiXactIdWait(multi, status, remaining, infomask, true);
05429 }
05430
05431
05432
05433
05434
05435
05436
05437
05438
05439
05440 bool
05441 heap_tuple_needs_freeze(HeapTupleHeader tuple, TransactionId cutoff_xid,
05442 MultiXactId cutoff_multi, Buffer buf)
05443 {
05444 TransactionId xid;
05445
05446 xid = HeapTupleHeaderGetXmin(tuple);
05447 if (TransactionIdIsNormal(xid) &&
05448 TransactionIdPrecedes(xid, cutoff_xid))
05449 return true;
05450
05451 if (!(tuple->t_infomask & HEAP_XMAX_INVALID))
05452 {
05453 if (!(tuple->t_infomask & HEAP_XMAX_IS_MULTI))
05454 {
05455 xid = HeapTupleHeaderGetRawXmax(tuple);
05456 if (TransactionIdIsNormal(xid) &&
05457 TransactionIdPrecedes(xid, cutoff_xid))
05458 return true;
05459 }
05460 else
05461 {
05462 MultiXactId multi;
05463
05464 multi = HeapTupleHeaderGetRawXmax(tuple);
05465 if (MultiXactIdPrecedes(multi, cutoff_multi))
05466 return true;
05467 }
05468 }
05469
05470 if (tuple->t_infomask & HEAP_MOVED)
05471 {
05472 xid = HeapTupleHeaderGetXvac(tuple);
05473 if (TransactionIdIsNormal(xid) &&
05474 TransactionIdPrecedes(xid, cutoff_xid))
05475 return true;
05476 }
05477
05478 return false;
05479 }
05480
05481
05482
05483
05484
05485 void
05486 heap_markpos(HeapScanDesc scan)
05487 {
05488
05489
05490 if (scan->rs_ctup.t_data != NULL)
05491 {
05492 scan->rs_mctid = scan->rs_ctup.t_self;
05493 if (scan->rs_pageatatime)
05494 scan->rs_mindex = scan->rs_cindex;
05495 }
05496 else
05497 ItemPointerSetInvalid(&scan->rs_mctid);
05498 }
05499
05500
05501
05502
05503
05504 void
05505 heap_restrpos(HeapScanDesc scan)
05506 {
05507
05508
05509 if (!ItemPointerIsValid(&scan->rs_mctid))
05510 {
05511 scan->rs_ctup.t_data = NULL;
05512
05513
05514
05515
05516 if (BufferIsValid(scan->rs_cbuf))
05517 ReleaseBuffer(scan->rs_cbuf);
05518 scan->rs_cbuf = InvalidBuffer;
05519 scan->rs_cblock = InvalidBlockNumber;
05520 scan->rs_inited = false;
05521 }
05522 else
05523 {
05524
05525
05526
05527
05528 scan->rs_inited = true;
05529 scan->rs_ctup.t_self = scan->rs_mctid;
05530 if (scan->rs_pageatatime)
05531 {
05532 scan->rs_cindex = scan->rs_mindex;
05533 heapgettup_pagemode(scan,
05534 NoMovementScanDirection,
05535 0,
05536 NULL);
05537 }
05538 else
05539 heapgettup(scan,
05540 NoMovementScanDirection,
05541 0,
05542 NULL);
05543 }
05544 }
05545
05546
05547
05548
05549
05550
05551
05552
05553 void
05554 HeapTupleHeaderAdvanceLatestRemovedXid(HeapTupleHeader tuple,
05555 TransactionId *latestRemovedXid)
05556 {
05557 TransactionId xmin = HeapTupleHeaderGetXmin(tuple);
05558 TransactionId xmax = HeapTupleHeaderGetUpdateXid(tuple);
05559 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
05560
05561 if (tuple->t_infomask & HEAP_MOVED)
05562 {
05563 if (TransactionIdPrecedes(*latestRemovedXid, xvac))
05564 *latestRemovedXid = xvac;
05565 }
05566
05567
05568
05569
05570
05571
05572
05573
05574
05575 if ((tuple->t_infomask & HEAP_XMIN_COMMITTED) ||
05576 (!(tuple->t_infomask & HEAP_XMIN_COMMITTED) &&
05577 !(tuple->t_infomask & HEAP_XMIN_INVALID) &&
05578 TransactionIdDidCommit(xmin)))
05579 {
05580 if (xmax != xmin &&
05581 TransactionIdFollows(xmax, *latestRemovedXid))
05582 *latestRemovedXid = xmax;
05583 }
05584
05585
05586 }
05587
05588
05589
05590
05591
05592
05593
05594 XLogRecPtr
05595 log_heap_cleanup_info(RelFileNode rnode, TransactionId latestRemovedXid)
05596 {
05597 xl_heap_cleanup_info xlrec;
05598 XLogRecPtr recptr;
05599 XLogRecData rdata;
05600
05601 xlrec.node = rnode;
05602 xlrec.latestRemovedXid = latestRemovedXid;
05603
05604 rdata.data = (char *) &xlrec;
05605 rdata.len = SizeOfHeapCleanupInfo;
05606 rdata.buffer = InvalidBuffer;
05607 rdata.next = NULL;
05608
05609 recptr = XLogInsert(RM_HEAP2_ID, XLOG_HEAP2_CLEANUP_INFO, &rdata);
05610
05611 return recptr;
05612 }
05613
05614
05615
05616
05617
05618
05619
05620
05621
05622
05623
05624
05625
05626 XLogRecPtr
05627 log_heap_clean(Relation reln, Buffer buffer,
05628 OffsetNumber *redirected, int nredirected,
05629 OffsetNumber *nowdead, int ndead,
05630 OffsetNumber *nowunused, int nunused,
05631 TransactionId latestRemovedXid)
05632 {
05633 xl_heap_clean xlrec;
05634 uint8 info;
05635 XLogRecPtr recptr;
05636 XLogRecData rdata[4];
05637
05638
05639 Assert(RelationNeedsWAL(reln));
05640
05641 xlrec.node = reln->rd_node;
05642 xlrec.block = BufferGetBlockNumber(buffer);
05643 xlrec.latestRemovedXid = latestRemovedXid;
05644 xlrec.nredirected = nredirected;
05645 xlrec.ndead = ndead;
05646
05647 rdata[0].data = (char *) &xlrec;
05648 rdata[0].len = SizeOfHeapClean;
05649 rdata[0].buffer = InvalidBuffer;
05650 rdata[0].next = &(rdata[1]);
05651
05652
05653
05654
05655
05656
05657
05658
05659
05660 if (nredirected > 0)
05661 {
05662 rdata[1].data = (char *) redirected;
05663 rdata[1].len = nredirected * sizeof(OffsetNumber) * 2;
05664 }
05665 else
05666 {
05667 rdata[1].data = NULL;
05668 rdata[1].len = 0;
05669 }
05670 rdata[1].buffer = buffer;
05671 rdata[1].buffer_std = true;
05672 rdata[1].next = &(rdata[2]);
05673
05674 if (ndead > 0)
05675 {
05676 rdata[2].data = (char *) nowdead;
05677 rdata[2].len = ndead * sizeof(OffsetNumber);
05678 }
05679 else
05680 {
05681 rdata[2].data = NULL;
05682 rdata[2].len = 0;
05683 }
05684 rdata[2].buffer = buffer;
05685 rdata[2].buffer_std = true;
05686 rdata[2].next = &(rdata[3]);
05687
05688 if (nunused > 0)
05689 {
05690 rdata[3].data = (char *) nowunused;
05691 rdata[3].len = nunused * sizeof(OffsetNumber);
05692 }
05693 else
05694 {
05695 rdata[3].data = NULL;
05696 rdata[3].len = 0;
05697 }
05698 rdata[3].buffer = buffer;
05699 rdata[3].buffer_std = true;
05700 rdata[3].next = NULL;
05701
05702 info = XLOG_HEAP2_CLEAN;
05703 recptr = XLogInsert(RM_HEAP2_ID, info, rdata);
05704
05705 return recptr;
05706 }
05707
05708
05709
05710
05711
05712 XLogRecPtr
05713 log_heap_freeze(Relation reln, Buffer buffer,
05714 TransactionId cutoff_xid, MultiXactId cutoff_multi,
05715 OffsetNumber *offsets, int offcnt)
05716 {
05717 xl_heap_freeze xlrec;
05718 XLogRecPtr recptr;
05719 XLogRecData rdata[2];
05720
05721
05722 Assert(RelationNeedsWAL(reln));
05723
05724 Assert(offcnt > 0);
05725
05726 xlrec.node = reln->rd_node;
05727 xlrec.block = BufferGetBlockNumber(buffer);
05728 xlrec.cutoff_xid = cutoff_xid;
05729 xlrec.cutoff_multi = cutoff_multi;
05730
05731 rdata[0].data = (char *) &xlrec;
05732 rdata[0].len = SizeOfHeapFreeze;
05733 rdata[0].buffer = InvalidBuffer;
05734 rdata[0].next = &(rdata[1]);
05735
05736
05737
05738
05739
05740
05741 rdata[1].data = (char *) offsets;
05742 rdata[1].len = offcnt * sizeof(OffsetNumber);
05743 rdata[1].buffer = buffer;
05744 rdata[1].buffer_std = true;
05745 rdata[1].next = NULL;
05746
05747 recptr = XLogInsert(RM_HEAP2_ID, XLOG_HEAP2_FREEZE, rdata);
05748
05749 return recptr;
05750 }
05751
05752
05753
05754
05755
05756
05757
05758
05759
05760
05761 XLogRecPtr
05762 log_heap_visible(RelFileNode rnode, Buffer heap_buffer, Buffer vm_buffer,
05763 TransactionId cutoff_xid)
05764 {
05765 xl_heap_visible xlrec;
05766 XLogRecPtr recptr;
05767 XLogRecData rdata[3];
05768
05769 Assert(BufferIsValid(heap_buffer));
05770 Assert(BufferIsValid(vm_buffer));
05771
05772 xlrec.node = rnode;
05773 xlrec.block = BufferGetBlockNumber(heap_buffer);
05774 xlrec.cutoff_xid = cutoff_xid;
05775
05776 rdata[0].data = (char *) &xlrec;
05777 rdata[0].len = SizeOfHeapVisible;
05778 rdata[0].buffer = InvalidBuffer;
05779 rdata[0].next = &(rdata[1]);
05780
05781 rdata[1].data = NULL;
05782 rdata[1].len = 0;
05783 rdata[1].buffer = vm_buffer;
05784 rdata[1].buffer_std = false;
05785 rdata[1].next = NULL;
05786
05787 if (DataChecksumsEnabled())
05788 {
05789 rdata[1].next = &(rdata[2]);
05790
05791 rdata[2].data = NULL;
05792 rdata[2].len = 0;
05793 rdata[2].buffer = heap_buffer;
05794 rdata[2].buffer_std = true;
05795 rdata[2].next = NULL;
05796 }
05797
05798 recptr = XLogInsert(RM_HEAP2_ID, XLOG_HEAP2_VISIBLE, rdata);
05799
05800 return recptr;
05801 }
05802
05803
05804
05805
05806
05807 static XLogRecPtr
05808 log_heap_update(Relation reln, Buffer oldbuf,
05809 Buffer newbuf, HeapTuple oldtup, HeapTuple newtup,
05810 bool all_visible_cleared, bool new_all_visible_cleared)
05811 {
05812 xl_heap_update xlrec;
05813 xl_heap_header xlhdr;
05814 uint8 info;
05815 XLogRecPtr recptr;
05816 XLogRecData rdata[4];
05817 Page page = BufferGetPage(newbuf);
05818
05819
05820 Assert(RelationNeedsWAL(reln));
05821
05822 if (HeapTupleIsHeapOnly(newtup))
05823 info = XLOG_HEAP_HOT_UPDATE;
05824 else
05825 info = XLOG_HEAP_UPDATE;
05826
05827 xlrec.target.node = reln->rd_node;
05828 xlrec.target.tid = oldtup->t_self;
05829 xlrec.old_xmax = HeapTupleHeaderGetRawXmax(oldtup->t_data);
05830 xlrec.old_infobits_set = compute_infobits(oldtup->t_data->t_infomask,
05831 oldtup->t_data->t_infomask2);
05832 xlrec.new_xmax = HeapTupleHeaderGetRawXmax(newtup->t_data);
05833 xlrec.all_visible_cleared = all_visible_cleared;
05834 xlrec.newtid = newtup->t_self;
05835 xlrec.new_all_visible_cleared = new_all_visible_cleared;
05836
05837 rdata[0].data = (char *) &xlrec;
05838 rdata[0].len = SizeOfHeapUpdate;
05839 rdata[0].buffer = InvalidBuffer;
05840 rdata[0].next = &(rdata[1]);
05841
05842 rdata[1].data = NULL;
05843 rdata[1].len = 0;
05844 rdata[1].buffer = oldbuf;
05845 rdata[1].buffer_std = true;
05846 rdata[1].next = &(rdata[2]);
05847
05848 xlhdr.t_infomask2 = newtup->t_data->t_infomask2;
05849 xlhdr.t_infomask = newtup->t_data->t_infomask;
05850 xlhdr.t_hoff = newtup->t_data->t_hoff;
05851
05852
05853
05854
05855
05856 rdata[2].data = (char *) &xlhdr;
05857 rdata[2].len = SizeOfHeapHeader;
05858 rdata[2].buffer = newbuf;
05859 rdata[2].buffer_std = true;
05860 rdata[2].next = &(rdata[3]);
05861
05862
05863 rdata[3].data = (char *) newtup->t_data + offsetof(HeapTupleHeaderData, t_bits);
05864 rdata[3].len = newtup->t_len - offsetof(HeapTupleHeaderData, t_bits);
05865 rdata[3].buffer = newbuf;
05866 rdata[3].buffer_std = true;
05867 rdata[3].next = NULL;
05868
05869
05870 if (ItemPointerGetOffsetNumber(&(newtup->t_self)) == FirstOffsetNumber &&
05871 PageGetMaxOffsetNumber(page) == FirstOffsetNumber)
05872 {
05873 info |= XLOG_HEAP_INIT_PAGE;
05874 rdata[2].buffer = rdata[3].buffer = InvalidBuffer;
05875 }
05876
05877 recptr = XLogInsert(RM_HEAP_ID, info, rdata);
05878
05879 return recptr;
05880 }
05881
05882
05883
05884
05885
05886
05887
05888
05889
05890
05891
05892
05893 XLogRecPtr
05894 log_newpage(RelFileNode *rnode, ForkNumber forkNum, BlockNumber blkno,
05895 Page page)
05896 {
05897 xl_heap_newpage xlrec;
05898 XLogRecPtr recptr;
05899 XLogRecData rdata[2];
05900
05901
05902 START_CRIT_SECTION();
05903
05904 xlrec.node = *rnode;
05905 xlrec.forknum = forkNum;
05906 xlrec.blkno = blkno;
05907
05908 rdata[0].data = (char *) &xlrec;
05909 rdata[0].len = SizeOfHeapNewpage;
05910 rdata[0].buffer = InvalidBuffer;
05911 rdata[0].next = &(rdata[1]);
05912
05913 rdata[1].data = (char *) page;
05914 rdata[1].len = BLCKSZ;
05915 rdata[1].buffer = InvalidBuffer;
05916 rdata[1].next = NULL;
05917
05918 recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_NEWPAGE, rdata);
05919
05920
05921
05922
05923
05924 if (!PageIsNew(page))
05925 {
05926 PageSetLSN(page, recptr);
05927 }
05928
05929 END_CRIT_SECTION();
05930
05931 return recptr;
05932 }
05933
05934
05935
05936
05937
05938
05939
05940
05941
05942
05943 XLogRecPtr
05944 log_newpage_buffer(Buffer buffer)
05945 {
05946 xl_heap_newpage xlrec;
05947 XLogRecPtr recptr;
05948 XLogRecData rdata[2];
05949 Page page = BufferGetPage(buffer);
05950
05951
05952 Assert(CritSectionCount > 0);
05953
05954 BufferGetTag(buffer, &xlrec.node, &xlrec.forknum, &xlrec.blkno);
05955
05956 rdata[0].data = (char *) &xlrec;
05957 rdata[0].len = SizeOfHeapNewpage;
05958 rdata[0].buffer = InvalidBuffer;
05959 rdata[0].next = &(rdata[1]);
05960
05961 rdata[1].data = page;
05962 rdata[1].len = BLCKSZ;
05963 rdata[1].buffer = InvalidBuffer;
05964 rdata[1].next = NULL;
05965
05966 recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_NEWPAGE, rdata);
05967
05968
05969
05970
05971
05972 if (!PageIsNew(page))
05973 {
05974 PageSetLSN(page, recptr);
05975 }
05976
05977 return recptr;
05978 }
05979
05980
05981
05982
05983 static void
05984 heap_xlog_cleanup_info(XLogRecPtr lsn, XLogRecord *record)
05985 {
05986 xl_heap_cleanup_info *xlrec = (xl_heap_cleanup_info *) XLogRecGetData(record);
05987
05988 if (InHotStandby)
05989 ResolveRecoveryConflictWithSnapshot(xlrec->latestRemovedXid, xlrec->node);
05990
05991
05992
05993
05994
05995
05996
05997
05998 Assert(!(record->xl_info & XLR_BKP_BLOCK_MASK));
05999 }
06000
06001
06002
06003
06004 static void
06005 heap_xlog_clean(XLogRecPtr lsn, XLogRecord *record)
06006 {
06007 xl_heap_clean *xlrec = (xl_heap_clean *) XLogRecGetData(record);
06008 Buffer buffer;
06009 Page page;
06010 OffsetNumber *end;
06011 OffsetNumber *redirected;
06012 OffsetNumber *nowdead;
06013 OffsetNumber *nowunused;
06014 int nredirected;
06015 int ndead;
06016 int nunused;
06017 Size freespace;
06018
06019
06020
06021
06022
06023
06024
06025
06026
06027 if (InHotStandby && TransactionIdIsValid(xlrec->latestRemovedXid))
06028 ResolveRecoveryConflictWithSnapshot(xlrec->latestRemovedXid,
06029 xlrec->node);
06030
06031
06032
06033
06034
06035 if (record->xl_info & XLR_BKP_BLOCK(0))
06036 {
06037 (void) RestoreBackupBlock(lsn, record, 0, true, false);
06038 return;
06039 }
06040
06041 buffer = XLogReadBufferExtended(xlrec->node, MAIN_FORKNUM, xlrec->block, RBM_NORMAL);
06042 if (!BufferIsValid(buffer))
06043 return;
06044 LockBufferForCleanup(buffer);
06045 page = (Page) BufferGetPage(buffer);
06046
06047 if (lsn <= PageGetLSN(page))
06048 {
06049 UnlockReleaseBuffer(buffer);
06050 return;
06051 }
06052
06053 nredirected = xlrec->nredirected;
06054 ndead = xlrec->ndead;
06055 end = (OffsetNumber *) ((char *) xlrec + record->xl_len);
06056 redirected = (OffsetNumber *) ((char *) xlrec + SizeOfHeapClean);
06057 nowdead = redirected + (nredirected * 2);
06058 nowunused = nowdead + ndead;
06059 nunused = (end - nowunused);
06060 Assert(nunused >= 0);
06061
06062
06063 heap_page_prune_execute(buffer,
06064 redirected, nredirected,
06065 nowdead, ndead,
06066 nowunused, nunused);
06067
06068 freespace = PageGetHeapFreeSpace(page);
06069
06070
06071
06072
06073
06074
06075 PageSetLSN(page, lsn);
06076 MarkBufferDirty(buffer);
06077 UnlockReleaseBuffer(buffer);
06078
06079
06080
06081
06082
06083
06084
06085
06086 XLogRecordPageWithFreeSpace(xlrec->node, xlrec->block, freespace);
06087 }
06088
06089 static void
06090 heap_xlog_freeze(XLogRecPtr lsn, XLogRecord *record)
06091 {
06092 xl_heap_freeze *xlrec = (xl_heap_freeze *) XLogRecGetData(record);
06093 TransactionId cutoff_xid = xlrec->cutoff_xid;
06094 MultiXactId cutoff_multi = xlrec->cutoff_multi;
06095 Buffer buffer;
06096 Page page;
06097
06098
06099
06100
06101
06102 if (InHotStandby)
06103 ResolveRecoveryConflictWithSnapshot(cutoff_xid, xlrec->node);
06104
06105
06106 if (record->xl_info & XLR_BKP_BLOCK(0))
06107 {
06108 (void) RestoreBackupBlock(lsn, record, 0, false, false);
06109 return;
06110 }
06111
06112 buffer = XLogReadBuffer(xlrec->node, xlrec->block, false);
06113 if (!BufferIsValid(buffer))
06114 return;
06115 page = (Page) BufferGetPage(buffer);
06116
06117 if (lsn <= PageGetLSN(page))
06118 {
06119 UnlockReleaseBuffer(buffer);
06120 return;
06121 }
06122
06123 if (record->xl_len > SizeOfHeapFreeze)
06124 {
06125 OffsetNumber *offsets;
06126 OffsetNumber *offsets_end;
06127
06128 offsets = (OffsetNumber *) ((char *) xlrec + SizeOfHeapFreeze);
06129 offsets_end = (OffsetNumber *) ((char *) xlrec + record->xl_len);
06130
06131 while (offsets < offsets_end)
06132 {
06133
06134 ItemId lp = PageGetItemId(page, *offsets);
06135 HeapTupleHeader tuple = (HeapTupleHeader) PageGetItem(page, lp);
06136
06137 (void) heap_freeze_tuple(tuple, cutoff_xid, cutoff_multi);
06138 offsets++;
06139 }
06140 }
06141
06142 PageSetLSN(page, lsn);
06143 MarkBufferDirty(buffer);
06144 UnlockReleaseBuffer(buffer);
06145 }
06146
06147
06148
06149
06150
06151
06152
06153
06154
06155 static void
06156 heap_xlog_visible(XLogRecPtr lsn, XLogRecord *record)
06157 {
06158 xl_heap_visible *xlrec = (xl_heap_visible *) XLogRecGetData(record);
06159
06160
06161
06162
06163
06164
06165
06166
06167
06168
06169 if (InHotStandby)
06170 ResolveRecoveryConflictWithSnapshot(xlrec->cutoff_xid, xlrec->node);
06171
06172
06173
06174
06175
06176 if (record->xl_info & XLR_BKP_BLOCK(1))
06177 {
06178 Assert(DataChecksumsEnabled());
06179 (void) RestoreBackupBlock(lsn, record, 1, false, false);
06180 }
06181 else
06182 {
06183 Buffer buffer;
06184 Page page;
06185
06186
06187
06188
06189
06190
06191 buffer = XLogReadBufferExtended(xlrec->node, MAIN_FORKNUM,
06192 xlrec->block, RBM_NORMAL);
06193 if (BufferIsValid(buffer))
06194 {
06195 LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
06196
06197 page = (Page) BufferGetPage(buffer);
06198
06199
06200
06201
06202
06203
06204
06205
06206
06207
06208
06209
06210
06211
06212
06213
06214 if (lsn > PageGetLSN(page))
06215 {
06216 PageSetAllVisible(page);
06217 MarkBufferDirty(buffer);
06218 }
06219
06220
06221 UnlockReleaseBuffer(buffer);
06222 }
06223 }
06224
06225
06226
06227
06228
06229
06230
06231 if (record->xl_info & XLR_BKP_BLOCK(0))
06232 (void) RestoreBackupBlock(lsn, record, 0, false, false);
06233 else
06234 {
06235 Relation reln;
06236 Buffer vmbuffer = InvalidBuffer;
06237
06238 reln = CreateFakeRelcacheEntry(xlrec->node);
06239 visibilitymap_pin(reln, xlrec->block, &vmbuffer);
06240
06241
06242
06243
06244
06245
06246
06247
06248
06249
06250
06251
06252 if (lsn > PageGetLSN(BufferGetPage(vmbuffer)))
06253 visibilitymap_set(reln, xlrec->block, InvalidBuffer, lsn, vmbuffer,
06254 xlrec->cutoff_xid);
06255
06256 ReleaseBuffer(vmbuffer);
06257 FreeFakeRelcacheEntry(reln);
06258 }
06259 }
06260
06261 static void
06262 heap_xlog_newpage(XLogRecPtr lsn, XLogRecord *record)
06263 {
06264 xl_heap_newpage *xlrec = (xl_heap_newpage *) XLogRecGetData(record);
06265 Buffer buffer;
06266 Page page;
06267
06268
06269 Assert(!(record->xl_info & XLR_BKP_BLOCK_MASK));
06270
06271
06272
06273
06274
06275 buffer = XLogReadBufferExtended(xlrec->node, xlrec->forknum, xlrec->blkno,
06276 RBM_ZERO);
06277 Assert(BufferIsValid(buffer));
06278 LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
06279 page = (Page) BufferGetPage(buffer);
06280
06281 Assert(record->xl_len == SizeOfHeapNewpage + BLCKSZ);
06282 memcpy(page, (char *) xlrec + SizeOfHeapNewpage, BLCKSZ);
06283
06284
06285
06286
06287
06288 if (!PageIsNew(page))
06289 {
06290 PageSetLSN(page, lsn);
06291 }
06292
06293 MarkBufferDirty(buffer);
06294 UnlockReleaseBuffer(buffer);
06295 }
06296
06297
06298
06299
06300
06301
06302
06303 static void
06304 fix_infomask_from_infobits(uint8 infobits, uint16 *infomask, uint16 *infomask2)
06305 {
06306 *infomask &= ~(HEAP_XMAX_IS_MULTI | HEAP_XMAX_LOCK_ONLY |
06307 HEAP_XMAX_KEYSHR_LOCK | HEAP_XMAX_EXCL_LOCK);
06308 *infomask2 &= ~HEAP_KEYS_UPDATED;
06309
06310 if (infobits & XLHL_XMAX_IS_MULTI)
06311 *infomask |= HEAP_XMAX_IS_MULTI;
06312 if (infobits & XLHL_XMAX_LOCK_ONLY)
06313 *infomask |= HEAP_XMAX_LOCK_ONLY;
06314 if (infobits & XLHL_XMAX_EXCL_LOCK)
06315 *infomask |= HEAP_XMAX_EXCL_LOCK;
06316
06317 if (infobits & XLHL_XMAX_KEYSHR_LOCK)
06318 *infomask |= HEAP_XMAX_KEYSHR_LOCK;
06319
06320 if (infobits & XLHL_KEYS_UPDATED)
06321 *infomask2 |= HEAP_KEYS_UPDATED;
06322 }
06323
06324 static void
06325 heap_xlog_delete(XLogRecPtr lsn, XLogRecord *record)
06326 {
06327 xl_heap_delete *xlrec = (xl_heap_delete *) XLogRecGetData(record);
06328 Buffer buffer;
06329 Page page;
06330 OffsetNumber offnum;
06331 ItemId lp = NULL;
06332 HeapTupleHeader htup;
06333 BlockNumber blkno;
06334
06335 blkno = ItemPointerGetBlockNumber(&(xlrec->target.tid));
06336
06337
06338
06339
06340
06341 if (xlrec->all_visible_cleared)
06342 {
06343 Relation reln = CreateFakeRelcacheEntry(xlrec->target.node);
06344 Buffer vmbuffer = InvalidBuffer;
06345
06346 visibilitymap_pin(reln, blkno, &vmbuffer);
06347 visibilitymap_clear(reln, blkno, vmbuffer);
06348 ReleaseBuffer(vmbuffer);
06349 FreeFakeRelcacheEntry(reln);
06350 }
06351
06352
06353 if (record->xl_info & XLR_BKP_BLOCK(0))
06354 {
06355 (void) RestoreBackupBlock(lsn, record, 0, false, false);
06356 return;
06357 }
06358
06359 buffer = XLogReadBuffer(xlrec->target.node, blkno, false);
06360 if (!BufferIsValid(buffer))
06361 return;
06362 page = (Page) BufferGetPage(buffer);
06363
06364 if (lsn <= PageGetLSN(page))
06365 {
06366 UnlockReleaseBuffer(buffer);
06367 return;
06368 }
06369
06370 offnum = ItemPointerGetOffsetNumber(&(xlrec->target.tid));
06371 if (PageGetMaxOffsetNumber(page) >= offnum)
06372 lp = PageGetItemId(page, offnum);
06373
06374 if (PageGetMaxOffsetNumber(page) < offnum || !ItemIdIsNormal(lp))
06375 elog(PANIC, "heap_delete_redo: invalid lp");
06376
06377 htup = (HeapTupleHeader) PageGetItem(page, lp);
06378
06379 htup->t_infomask &= ~(HEAP_XMAX_BITS | HEAP_MOVED);
06380 htup->t_infomask2 &= ~HEAP_KEYS_UPDATED;
06381 HeapTupleHeaderClearHotUpdated(htup);
06382 fix_infomask_from_infobits(xlrec->infobits_set,
06383 &htup->t_infomask, &htup->t_infomask2);
06384 HeapTupleHeaderSetXmax(htup, xlrec->xmax);
06385 HeapTupleHeaderSetCmax(htup, FirstCommandId, false);
06386
06387
06388 PageSetPrunable(page, record->xl_xid);
06389
06390 if (xlrec->all_visible_cleared)
06391 PageClearAllVisible(page);
06392
06393
06394 htup->t_ctid = xlrec->target.tid;
06395 PageSetLSN(page, lsn);
06396 MarkBufferDirty(buffer);
06397 UnlockReleaseBuffer(buffer);
06398 }
06399
06400 static void
06401 heap_xlog_insert(XLogRecPtr lsn, XLogRecord *record)
06402 {
06403 xl_heap_insert *xlrec = (xl_heap_insert *) XLogRecGetData(record);
06404 Buffer buffer;
06405 Page page;
06406 OffsetNumber offnum;
06407 struct
06408 {
06409 HeapTupleHeaderData hdr;
06410 char data[MaxHeapTupleSize];
06411 } tbuf;
06412 HeapTupleHeader htup;
06413 xl_heap_header xlhdr;
06414 uint32 newlen;
06415 Size freespace;
06416 BlockNumber blkno;
06417
06418 blkno = ItemPointerGetBlockNumber(&(xlrec->target.tid));
06419
06420
06421
06422
06423
06424 if (xlrec->all_visible_cleared)
06425 {
06426 Relation reln = CreateFakeRelcacheEntry(xlrec->target.node);
06427 Buffer vmbuffer = InvalidBuffer;
06428
06429 visibilitymap_pin(reln, blkno, &vmbuffer);
06430 visibilitymap_clear(reln, blkno, vmbuffer);
06431 ReleaseBuffer(vmbuffer);
06432 FreeFakeRelcacheEntry(reln);
06433 }
06434
06435
06436 if (record->xl_info & XLR_BKP_BLOCK(0))
06437 {
06438 (void) RestoreBackupBlock(lsn, record, 0, false, false);
06439 return;
06440 }
06441
06442 if (record->xl_info & XLOG_HEAP_INIT_PAGE)
06443 {
06444 buffer = XLogReadBuffer(xlrec->target.node, blkno, true);
06445 Assert(BufferIsValid(buffer));
06446 page = (Page) BufferGetPage(buffer);
06447
06448 PageInit(page, BufferGetPageSize(buffer), 0);
06449 }
06450 else
06451 {
06452 buffer = XLogReadBuffer(xlrec->target.node, blkno, false);
06453 if (!BufferIsValid(buffer))
06454 return;
06455 page = (Page) BufferGetPage(buffer);
06456
06457 if (lsn <= PageGetLSN(page))
06458 {
06459 UnlockReleaseBuffer(buffer);
06460 return;
06461 }
06462 }
06463
06464 offnum = ItemPointerGetOffsetNumber(&(xlrec->target.tid));
06465 if (PageGetMaxOffsetNumber(page) + 1 < offnum)
06466 elog(PANIC, "heap_insert_redo: invalid max offset number");
06467
06468 newlen = record->xl_len - SizeOfHeapInsert - SizeOfHeapHeader;
06469 Assert(newlen <= MaxHeapTupleSize);
06470 memcpy((char *) &xlhdr,
06471 (char *) xlrec + SizeOfHeapInsert,
06472 SizeOfHeapHeader);
06473 htup = &tbuf.hdr;
06474 MemSet((char *) htup, 0, sizeof(HeapTupleHeaderData));
06475
06476 memcpy((char *) htup + offsetof(HeapTupleHeaderData, t_bits),
06477 (char *) xlrec + SizeOfHeapInsert + SizeOfHeapHeader,
06478 newlen);
06479 newlen += offsetof(HeapTupleHeaderData, t_bits);
06480 htup->t_infomask2 = xlhdr.t_infomask2;
06481 htup->t_infomask = xlhdr.t_infomask;
06482 htup->t_hoff = xlhdr.t_hoff;
06483 HeapTupleHeaderSetXmin(htup, record->xl_xid);
06484 HeapTupleHeaderSetCmin(htup, FirstCommandId);
06485 htup->t_ctid = xlrec->target.tid;
06486
06487 offnum = PageAddItem(page, (Item) htup, newlen, offnum, true, true);
06488 if (offnum == InvalidOffsetNumber)
06489 elog(PANIC, "heap_insert_redo: failed to add tuple");
06490
06491 freespace = PageGetHeapFreeSpace(page);
06492
06493 PageSetLSN(page, lsn);
06494
06495 if (xlrec->all_visible_cleared)
06496 PageClearAllVisible(page);
06497
06498 MarkBufferDirty(buffer);
06499 UnlockReleaseBuffer(buffer);
06500
06501
06502
06503
06504
06505
06506
06507
06508
06509
06510 if (freespace < BLCKSZ / 5)
06511 XLogRecordPageWithFreeSpace(xlrec->target.node, blkno, freespace);
06512 }
06513
06514
06515
06516
06517 static void
06518 heap_xlog_multi_insert(XLogRecPtr lsn, XLogRecord *record)
06519 {
06520 char *recdata = XLogRecGetData(record);
06521 xl_heap_multi_insert *xlrec;
06522 Buffer buffer;
06523 Page page;
06524 struct
06525 {
06526 HeapTupleHeaderData hdr;
06527 char data[MaxHeapTupleSize];
06528 } tbuf;
06529 HeapTupleHeader htup;
06530 uint32 newlen;
06531 Size freespace;
06532 BlockNumber blkno;
06533 int i;
06534 bool isinit = (record->xl_info & XLOG_HEAP_INIT_PAGE) != 0;
06535
06536
06537
06538
06539
06540
06541 xlrec = (xl_heap_multi_insert *) recdata;
06542 recdata += SizeOfHeapMultiInsert;
06543
06544
06545
06546
06547
06548
06549 if (!isinit)
06550 recdata += sizeof(OffsetNumber) * xlrec->ntuples;
06551
06552 blkno = xlrec->blkno;
06553
06554
06555
06556
06557
06558 if (xlrec->all_visible_cleared)
06559 {
06560 Relation reln = CreateFakeRelcacheEntry(xlrec->node);
06561 Buffer vmbuffer = InvalidBuffer;
06562
06563 visibilitymap_pin(reln, blkno, &vmbuffer);
06564 visibilitymap_clear(reln, blkno, vmbuffer);
06565 ReleaseBuffer(vmbuffer);
06566 FreeFakeRelcacheEntry(reln);
06567 }
06568
06569
06570 if (record->xl_info & XLR_BKP_BLOCK(0))
06571 {
06572 (void) RestoreBackupBlock(lsn, record, 0, false, false);
06573 return;
06574 }
06575
06576 if (isinit)
06577 {
06578 buffer = XLogReadBuffer(xlrec->node, blkno, true);
06579 Assert(BufferIsValid(buffer));
06580 page = (Page) BufferGetPage(buffer);
06581
06582 PageInit(page, BufferGetPageSize(buffer), 0);
06583 }
06584 else
06585 {
06586 buffer = XLogReadBuffer(xlrec->node, blkno, false);
06587 if (!BufferIsValid(buffer))
06588 return;
06589 page = (Page) BufferGetPage(buffer);
06590
06591 if (lsn <= PageGetLSN(page))
06592 {
06593 UnlockReleaseBuffer(buffer);
06594 return;
06595 }
06596 }
06597
06598 for (i = 0; i < xlrec->ntuples; i++)
06599 {
06600 OffsetNumber offnum;
06601 xl_multi_insert_tuple *xlhdr;
06602
06603 if (isinit)
06604 offnum = FirstOffsetNumber + i;
06605 else
06606 offnum = xlrec->offsets[i];
06607 if (PageGetMaxOffsetNumber(page) + 1 < offnum)
06608 elog(PANIC, "heap_multi_insert_redo: invalid max offset number");
06609
06610 xlhdr = (xl_multi_insert_tuple *) SHORTALIGN(recdata);
06611 recdata = ((char *) xlhdr) + SizeOfMultiInsertTuple;
06612
06613 newlen = xlhdr->datalen;
06614 Assert(newlen <= MaxHeapTupleSize);
06615 htup = &tbuf.hdr;
06616 MemSet((char *) htup, 0, sizeof(HeapTupleHeaderData));
06617
06618 memcpy((char *) htup + offsetof(HeapTupleHeaderData, t_bits),
06619 (char *) recdata,
06620 newlen);
06621 recdata += newlen;
06622
06623 newlen += offsetof(HeapTupleHeaderData, t_bits);
06624 htup->t_infomask2 = xlhdr->t_infomask2;
06625 htup->t_infomask = xlhdr->t_infomask;
06626 htup->t_hoff = xlhdr->t_hoff;
06627 HeapTupleHeaderSetXmin(htup, record->xl_xid);
06628 HeapTupleHeaderSetCmin(htup, FirstCommandId);
06629 ItemPointerSetBlockNumber(&htup->t_ctid, blkno);
06630 ItemPointerSetOffsetNumber(&htup->t_ctid, offnum);
06631
06632 offnum = PageAddItem(page, (Item) htup, newlen, offnum, true, true);
06633 if (offnum == InvalidOffsetNumber)
06634 elog(PANIC, "heap_multi_insert_redo: failed to add tuple");
06635 }
06636
06637 freespace = PageGetHeapFreeSpace(page);
06638
06639 PageSetLSN(page, lsn);
06640
06641 if (xlrec->all_visible_cleared)
06642 PageClearAllVisible(page);
06643
06644 MarkBufferDirty(buffer);
06645 UnlockReleaseBuffer(buffer);
06646
06647
06648
06649
06650
06651
06652
06653
06654
06655
06656 if (freespace < BLCKSZ / 5)
06657 XLogRecordPageWithFreeSpace(xlrec->node, blkno, freespace);
06658 }
06659
06660
06661
06662
06663 static void
06664 heap_xlog_update(XLogRecPtr lsn, XLogRecord *record, bool hot_update)
06665 {
06666 xl_heap_update *xlrec = (xl_heap_update *) XLogRecGetData(record);
06667 bool samepage = (ItemPointerGetBlockNumber(&(xlrec->newtid)) ==
06668 ItemPointerGetBlockNumber(&(xlrec->target.tid)));
06669 Buffer obuffer,
06670 nbuffer;
06671 Page page;
06672 OffsetNumber offnum;
06673 ItemId lp = NULL;
06674 HeapTupleHeader htup;
06675 struct
06676 {
06677 HeapTupleHeaderData hdr;
06678 char data[MaxHeapTupleSize];
06679 } tbuf;
06680 xl_heap_header xlhdr;
06681 int hsize;
06682 uint32 newlen;
06683 Size freespace;
06684
06685
06686
06687
06688
06689 if (xlrec->all_visible_cleared)
06690 {
06691 Relation reln = CreateFakeRelcacheEntry(xlrec->target.node);
06692 BlockNumber block = ItemPointerGetBlockNumber(&xlrec->target.tid);
06693 Buffer vmbuffer = InvalidBuffer;
06694
06695 visibilitymap_pin(reln, block, &vmbuffer);
06696 visibilitymap_clear(reln, block, vmbuffer);
06697 ReleaseBuffer(vmbuffer);
06698 FreeFakeRelcacheEntry(reln);
06699 }
06700
06701
06702
06703
06704
06705
06706
06707
06708
06709
06710
06711 if (record->xl_info & XLR_BKP_BLOCK(0))
06712 {
06713 obuffer = RestoreBackupBlock(lsn, record, 0, false, true);
06714 if (samepage)
06715 {
06716
06717 UnlockReleaseBuffer(obuffer);
06718 return;
06719 }
06720 goto newt;
06721 }
06722
06723
06724
06725 obuffer = XLogReadBuffer(xlrec->target.node,
06726 ItemPointerGetBlockNumber(&(xlrec->target.tid)),
06727 false);
06728 if (!BufferIsValid(obuffer))
06729 goto newt;
06730 page = (Page) BufferGetPage(obuffer);
06731
06732 if (lsn <= PageGetLSN(page))
06733 {
06734 if (samepage)
06735 {
06736 UnlockReleaseBuffer(obuffer);
06737 return;
06738 }
06739 goto newt;
06740 }
06741
06742 offnum = ItemPointerGetOffsetNumber(&(xlrec->target.tid));
06743 if (PageGetMaxOffsetNumber(page) >= offnum)
06744 lp = PageGetItemId(page, offnum);
06745
06746 if (PageGetMaxOffsetNumber(page) < offnum || !ItemIdIsNormal(lp))
06747 elog(PANIC, "heap_update_redo: invalid lp");
06748
06749 htup = (HeapTupleHeader) PageGetItem(page, lp);
06750
06751 htup->t_infomask &= ~(HEAP_XMAX_BITS | HEAP_MOVED);
06752 htup->t_infomask2 &= ~HEAP_KEYS_UPDATED;
06753 if (hot_update)
06754 HeapTupleHeaderSetHotUpdated(htup);
06755 else
06756 HeapTupleHeaderClearHotUpdated(htup);
06757 fix_infomask_from_infobits(xlrec->old_infobits_set, &htup->t_infomask,
06758 &htup->t_infomask2);
06759 HeapTupleHeaderSetXmax(htup, xlrec->old_xmax);
06760 HeapTupleHeaderSetCmax(htup, FirstCommandId, false);
06761
06762 htup->t_ctid = xlrec->newtid;
06763
06764
06765 PageSetPrunable(page, record->xl_xid);
06766
06767 if (xlrec->all_visible_cleared)
06768 PageClearAllVisible(page);
06769
06770
06771
06772
06773
06774 if (samepage)
06775 {
06776 nbuffer = obuffer;
06777 goto newsame;
06778 }
06779
06780 PageSetLSN(page, lsn);
06781 MarkBufferDirty(obuffer);
06782
06783
06784
06785 newt:;
06786
06787
06788
06789
06790
06791 if (xlrec->new_all_visible_cleared)
06792 {
06793 Relation reln = CreateFakeRelcacheEntry(xlrec->target.node);
06794 BlockNumber block = ItemPointerGetBlockNumber(&xlrec->newtid);
06795 Buffer vmbuffer = InvalidBuffer;
06796
06797 visibilitymap_pin(reln, block, &vmbuffer);
06798 visibilitymap_clear(reln, block, vmbuffer);
06799 ReleaseBuffer(vmbuffer);
06800 FreeFakeRelcacheEntry(reln);
06801 }
06802
06803 if (record->xl_info & XLR_BKP_BLOCK(1))
06804 {
06805 (void) RestoreBackupBlock(lsn, record, 1, false, false);
06806 if (BufferIsValid(obuffer))
06807 UnlockReleaseBuffer(obuffer);
06808 return;
06809 }
06810
06811 if (record->xl_info & XLOG_HEAP_INIT_PAGE)
06812 {
06813 nbuffer = XLogReadBuffer(xlrec->target.node,
06814 ItemPointerGetBlockNumber(&(xlrec->newtid)),
06815 true);
06816 Assert(BufferIsValid(nbuffer));
06817 page = (Page) BufferGetPage(nbuffer);
06818
06819 PageInit(page, BufferGetPageSize(nbuffer), 0);
06820 }
06821 else
06822 {
06823 nbuffer = XLogReadBuffer(xlrec->target.node,
06824 ItemPointerGetBlockNumber(&(xlrec->newtid)),
06825 false);
06826 if (!BufferIsValid(nbuffer))
06827 {
06828 if (BufferIsValid(obuffer))
06829 UnlockReleaseBuffer(obuffer);
06830 return;
06831 }
06832 page = (Page) BufferGetPage(nbuffer);
06833
06834 if (lsn <= PageGetLSN(page))
06835 {
06836 UnlockReleaseBuffer(nbuffer);
06837 if (BufferIsValid(obuffer))
06838 UnlockReleaseBuffer(obuffer);
06839 return;
06840 }
06841 }
06842
06843 newsame:;
06844
06845 offnum = ItemPointerGetOffsetNumber(&(xlrec->newtid));
06846 if (PageGetMaxOffsetNumber(page) + 1 < offnum)
06847 elog(PANIC, "heap_update_redo: invalid max offset number");
06848
06849 hsize = SizeOfHeapUpdate + SizeOfHeapHeader;
06850
06851 newlen = record->xl_len - hsize;
06852 Assert(newlen <= MaxHeapTupleSize);
06853 memcpy((char *) &xlhdr,
06854 (char *) xlrec + SizeOfHeapUpdate,
06855 SizeOfHeapHeader);
06856 htup = &tbuf.hdr;
06857 MemSet((char *) htup, 0, sizeof(HeapTupleHeaderData));
06858
06859 memcpy((char *) htup + offsetof(HeapTupleHeaderData, t_bits),
06860 (char *) xlrec + hsize,
06861 newlen);
06862 newlen += offsetof(HeapTupleHeaderData, t_bits);
06863 htup->t_infomask2 = xlhdr.t_infomask2;
06864 htup->t_infomask = xlhdr.t_infomask;
06865 htup->t_hoff = xlhdr.t_hoff;
06866
06867 HeapTupleHeaderSetXmin(htup, record->xl_xid);
06868 HeapTupleHeaderSetCmin(htup, FirstCommandId);
06869 HeapTupleHeaderSetXmax(htup, xlrec->new_xmax);
06870
06871 htup->t_ctid = xlrec->newtid;
06872
06873 offnum = PageAddItem(page, (Item) htup, newlen, offnum, true, true);
06874 if (offnum == InvalidOffsetNumber)
06875 elog(PANIC, "heap_update_redo: failed to add tuple");
06876
06877 if (xlrec->new_all_visible_cleared)
06878 PageClearAllVisible(page);
06879
06880 freespace = PageGetHeapFreeSpace(page);
06881
06882 PageSetLSN(page, lsn);
06883 MarkBufferDirty(nbuffer);
06884 UnlockReleaseBuffer(nbuffer);
06885
06886 if (BufferIsValid(obuffer) && obuffer != nbuffer)
06887 UnlockReleaseBuffer(obuffer);
06888
06889
06890
06891
06892
06893
06894
06895
06896
06897
06898
06899
06900
06901
06902
06903
06904 if (!hot_update && freespace < BLCKSZ / 5)
06905 XLogRecordPageWithFreeSpace(xlrec->target.node,
06906 ItemPointerGetBlockNumber(&(xlrec->newtid)),
06907 freespace);
06908 }
06909
06910 static void
06911 heap_xlog_lock(XLogRecPtr lsn, XLogRecord *record)
06912 {
06913 xl_heap_lock *xlrec = (xl_heap_lock *) XLogRecGetData(record);
06914 Buffer buffer;
06915 Page page;
06916 OffsetNumber offnum;
06917 ItemId lp = NULL;
06918 HeapTupleHeader htup;
06919
06920
06921 if (record->xl_info & XLR_BKP_BLOCK(0))
06922 {
06923 (void) RestoreBackupBlock(lsn, record, 0, false, false);
06924 return;
06925 }
06926
06927 buffer = XLogReadBuffer(xlrec->target.node,
06928 ItemPointerGetBlockNumber(&(xlrec->target.tid)),
06929 false);
06930 if (!BufferIsValid(buffer))
06931 return;
06932 page = (Page) BufferGetPage(buffer);
06933
06934 if (lsn <= PageGetLSN(page))
06935 {
06936 UnlockReleaseBuffer(buffer);
06937 return;
06938 }
06939
06940 offnum = ItemPointerGetOffsetNumber(&(xlrec->target.tid));
06941 if (PageGetMaxOffsetNumber(page) >= offnum)
06942 lp = PageGetItemId(page, offnum);
06943
06944 if (PageGetMaxOffsetNumber(page) < offnum || !ItemIdIsNormal(lp))
06945 elog(PANIC, "heap_lock_redo: invalid lp");
06946
06947 htup = (HeapTupleHeader) PageGetItem(page, lp);
06948
06949 fix_infomask_from_infobits(xlrec->infobits_set, &htup->t_infomask,
06950 &htup->t_infomask2);
06951 HeapTupleHeaderClearHotUpdated(htup);
06952 HeapTupleHeaderSetXmax(htup, xlrec->locking_xid);
06953 HeapTupleHeaderSetCmax(htup, FirstCommandId, false);
06954
06955 htup->t_ctid = xlrec->target.tid;
06956 PageSetLSN(page, lsn);
06957 MarkBufferDirty(buffer);
06958 UnlockReleaseBuffer(buffer);
06959 }
06960
06961 static void
06962 heap_xlog_lock_updated(XLogRecPtr lsn, XLogRecord *record)
06963 {
06964 xl_heap_lock_updated *xlrec =
06965 (xl_heap_lock_updated *) XLogRecGetData(record);
06966 Buffer buffer;
06967 Page page;
06968 OffsetNumber offnum;
06969 ItemId lp = NULL;
06970 HeapTupleHeader htup;
06971
06972
06973 if (record->xl_info & XLR_BKP_BLOCK(0))
06974 {
06975 (void) RestoreBackupBlock(lsn, record, 0, false, false);
06976 return;
06977 }
06978
06979 buffer = XLogReadBuffer(xlrec->target.node,
06980 ItemPointerGetBlockNumber(&(xlrec->target.tid)),
06981 false);
06982 if (!BufferIsValid(buffer))
06983 return;
06984 page = (Page) BufferGetPage(buffer);
06985
06986 if (lsn <= PageGetLSN(page))
06987 {
06988 UnlockReleaseBuffer(buffer);
06989 return;
06990 }
06991
06992 offnum = ItemPointerGetOffsetNumber(&(xlrec->target.tid));
06993 if (PageGetMaxOffsetNumber(page) >= offnum)
06994 lp = PageGetItemId(page, offnum);
06995
06996 if (PageGetMaxOffsetNumber(page) < offnum || !ItemIdIsNormal(lp))
06997 elog(PANIC, "heap_xlog_lock_updated: invalid lp");
06998
06999 htup = (HeapTupleHeader) PageGetItem(page, lp);
07000
07001 fix_infomask_from_infobits(xlrec->infobits_set, &htup->t_infomask,
07002 &htup->t_infomask2);
07003 HeapTupleHeaderSetXmax(htup, xlrec->xmax);
07004
07005 PageSetLSN(page, lsn);
07006 MarkBufferDirty(buffer);
07007 UnlockReleaseBuffer(buffer);
07008 }
07009
07010 static void
07011 heap_xlog_inplace(XLogRecPtr lsn, XLogRecord *record)
07012 {
07013 xl_heap_inplace *xlrec = (xl_heap_inplace *) XLogRecGetData(record);
07014 Buffer buffer;
07015 Page page;
07016 OffsetNumber offnum;
07017 ItemId lp = NULL;
07018 HeapTupleHeader htup;
07019 uint32 oldlen;
07020 uint32 newlen;
07021
07022
07023 if (record->xl_info & XLR_BKP_BLOCK(0))
07024 {
07025 (void) RestoreBackupBlock(lsn, record, 0, false, false);
07026 return;
07027 }
07028
07029 buffer = XLogReadBuffer(xlrec->target.node,
07030 ItemPointerGetBlockNumber(&(xlrec->target.tid)),
07031 false);
07032 if (!BufferIsValid(buffer))
07033 return;
07034 page = (Page) BufferGetPage(buffer);
07035
07036 if (lsn <= PageGetLSN(page))
07037 {
07038 UnlockReleaseBuffer(buffer);
07039 return;
07040 }
07041
07042 offnum = ItemPointerGetOffsetNumber(&(xlrec->target.tid));
07043 if (PageGetMaxOffsetNumber(page) >= offnum)
07044 lp = PageGetItemId(page, offnum);
07045
07046 if (PageGetMaxOffsetNumber(page) < offnum || !ItemIdIsNormal(lp))
07047 elog(PANIC, "heap_inplace_redo: invalid lp");
07048
07049 htup = (HeapTupleHeader) PageGetItem(page, lp);
07050
07051 oldlen = ItemIdGetLength(lp) - htup->t_hoff;
07052 newlen = record->xl_len - SizeOfHeapInplace;
07053 if (oldlen != newlen)
07054 elog(PANIC, "heap_inplace_redo: wrong tuple length");
07055
07056 memcpy((char *) htup + htup->t_hoff,
07057 (char *) xlrec + SizeOfHeapInplace,
07058 newlen);
07059
07060 PageSetLSN(page, lsn);
07061 MarkBufferDirty(buffer);
07062 UnlockReleaseBuffer(buffer);
07063 }
07064
07065 void
07066 heap_redo(XLogRecPtr lsn, XLogRecord *record)
07067 {
07068 uint8 info = record->xl_info & ~XLR_INFO_MASK;
07069
07070
07071
07072
07073
07074
07075 switch (info & XLOG_HEAP_OPMASK)
07076 {
07077 case XLOG_HEAP_INSERT:
07078 heap_xlog_insert(lsn, record);
07079 break;
07080 case XLOG_HEAP_DELETE:
07081 heap_xlog_delete(lsn, record);
07082 break;
07083 case XLOG_HEAP_UPDATE:
07084 heap_xlog_update(lsn, record, false);
07085 break;
07086 case XLOG_HEAP_HOT_UPDATE:
07087 heap_xlog_update(lsn, record, true);
07088 break;
07089 case XLOG_HEAP_NEWPAGE:
07090 heap_xlog_newpage(lsn, record);
07091 break;
07092 case XLOG_HEAP_LOCK:
07093 heap_xlog_lock(lsn, record);
07094 break;
07095 case XLOG_HEAP_INPLACE:
07096 heap_xlog_inplace(lsn, record);
07097 break;
07098 default:
07099 elog(PANIC, "heap_redo: unknown op code %u", info);
07100 }
07101 }
07102
07103 void
07104 heap2_redo(XLogRecPtr lsn, XLogRecord *record)
07105 {
07106 uint8 info = record->xl_info & ~XLR_INFO_MASK;
07107
07108 switch (info & XLOG_HEAP_OPMASK)
07109 {
07110 case XLOG_HEAP2_FREEZE:
07111 heap_xlog_freeze(lsn, record);
07112 break;
07113 case XLOG_HEAP2_CLEAN:
07114 heap_xlog_clean(lsn, record);
07115 break;
07116 case XLOG_HEAP2_CLEANUP_INFO:
07117 heap_xlog_cleanup_info(lsn, record);
07118 break;
07119 case XLOG_HEAP2_VISIBLE:
07120 heap_xlog_visible(lsn, record);
07121 break;
07122 case XLOG_HEAP2_MULTI_INSERT:
07123 heap_xlog_multi_insert(lsn, record);
07124 break;
07125 case XLOG_HEAP2_LOCK_UPDATED:
07126 heap_xlog_lock_updated(lsn, record);
07127 break;
07128 default:
07129 elog(PANIC, "heap2_redo: unknown op code %u", info);
07130 }
07131 }
07132
07133
07134
07135
07136
07137
07138
07139
07140
07141
07142
07143
07144
07145
07146
07147 void
07148 heap_sync(Relation rel)
07149 {
07150
07151 if (!RelationNeedsWAL(rel))
07152 return;
07153
07154
07155 FlushRelationBuffers(rel);
07156
07157 smgrimmedsync(rel->rd_smgr, MAIN_FORKNUM);
07158
07159
07160
07161
07162 if (OidIsValid(rel->rd_rel->reltoastrelid))
07163 {
07164 Relation toastrel;
07165
07166 toastrel = heap_open(rel->rd_rel->reltoastrelid, AccessShareLock);
07167 FlushRelationBuffers(toastrel);
07168 smgrimmedsync(toastrel->rd_smgr, MAIN_FORKNUM);
07169 heap_close(toastrel, AccessShareLock);
07170 }
07171 }