00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "postgres.h"
00020
00021 #include "access/heapam_xlog.h"
00022 #include "access/nbtree.h"
00023 #include "access/relscan.h"
00024 #include "catalog/index.h"
00025 #include "commands/vacuum.h"
00026 #include "storage/indexfsm.h"
00027 #include "storage/ipc.h"
00028 #include "storage/lmgr.h"
00029 #include "storage/smgr.h"
00030 #include "tcop/tcopprot.h"
00031 #include "utils/memutils.h"
00032
00033
00034
00035 typedef struct
00036 {
00037 bool isUnique;
00038 bool haveDead;
00039 Relation heapRel;
00040 BTSpool *spool;
00041
00042
00043
00044
00045
00046
00047 BTSpool *spool2;
00048 double indtuples;
00049 } BTBuildState;
00050
00051
00052 typedef struct
00053 {
00054 IndexVacuumInfo *info;
00055 IndexBulkDeleteResult *stats;
00056 IndexBulkDeleteCallback callback;
00057 void *callback_state;
00058 BTCycleId cycleid;
00059 BlockNumber lastBlockVacuumed;
00060 BlockNumber lastUsedPage;
00061 BlockNumber totFreePages;
00062 MemoryContext pagedelcontext;
00063 } BTVacState;
00064
00065
00066 static void btbuildCallback(Relation index,
00067 HeapTuple htup,
00068 Datum *values,
00069 bool *isnull,
00070 bool tupleIsAlive,
00071 void *state);
00072 static void btvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
00073 IndexBulkDeleteCallback callback, void *callback_state,
00074 BTCycleId cycleid);
00075 static void btvacuumpage(BTVacState *vstate, BlockNumber blkno,
00076 BlockNumber orig_blkno);
00077
00078
00079
00080
00081
00082 Datum
00083 btbuild(PG_FUNCTION_ARGS)
00084 {
00085 Relation heap = (Relation) PG_GETARG_POINTER(0);
00086 Relation index = (Relation) PG_GETARG_POINTER(1);
00087 IndexInfo *indexInfo = (IndexInfo *) PG_GETARG_POINTER(2);
00088 IndexBuildResult *result;
00089 double reltuples;
00090 BTBuildState buildstate;
00091
00092 buildstate.isUnique = indexInfo->ii_Unique;
00093 buildstate.haveDead = false;
00094 buildstate.heapRel = heap;
00095 buildstate.spool = NULL;
00096 buildstate.spool2 = NULL;
00097 buildstate.indtuples = 0;
00098
00099 #ifdef BTREE_BUILD_STATS
00100 if (log_btree_build_stats)
00101 ResetUsage();
00102 #endif
00103
00104
00105
00106
00107
00108 if (RelationGetNumberOfBlocks(index) != 0)
00109 elog(ERROR, "index \"%s\" already contains data",
00110 RelationGetRelationName(index));
00111
00112 buildstate.spool = _bt_spoolinit(heap, index, indexInfo->ii_Unique, false);
00113
00114
00115
00116
00117
00118 if (indexInfo->ii_Unique)
00119 buildstate.spool2 = _bt_spoolinit(heap, index, false, true);
00120
00121
00122 reltuples = IndexBuildHeapScan(heap, index, indexInfo, true,
00123 btbuildCallback, (void *) &buildstate);
00124
00125
00126 if (buildstate.spool2 && !buildstate.haveDead)
00127 {
00128
00129 _bt_spooldestroy(buildstate.spool2);
00130 buildstate.spool2 = NULL;
00131 }
00132
00133
00134
00135
00136
00137
00138 _bt_leafbuild(buildstate.spool, buildstate.spool2);
00139 _bt_spooldestroy(buildstate.spool);
00140 if (buildstate.spool2)
00141 _bt_spooldestroy(buildstate.spool2);
00142
00143 #ifdef BTREE_BUILD_STATS
00144 if (log_btree_build_stats)
00145 {
00146 ShowUsage("BTREE BUILD STATS");
00147 ResetUsage();
00148 }
00149 #endif
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162 result = (IndexBuildResult *) palloc(sizeof(IndexBuildResult));
00163
00164 result->heap_tuples = reltuples;
00165 result->index_tuples = buildstate.indtuples;
00166
00167 PG_RETURN_POINTER(result);
00168 }
00169
00170
00171
00172
00173 static void
00174 btbuildCallback(Relation index,
00175 HeapTuple htup,
00176 Datum *values,
00177 bool *isnull,
00178 bool tupleIsAlive,
00179 void *state)
00180 {
00181 BTBuildState *buildstate = (BTBuildState *) state;
00182 IndexTuple itup;
00183
00184
00185 itup = index_form_tuple(RelationGetDescr(index), values, isnull);
00186 itup->t_tid = htup->t_self;
00187
00188
00189
00190
00191
00192 if (tupleIsAlive || buildstate->spool2 == NULL)
00193 _bt_spool(itup, buildstate->spool);
00194 else
00195 {
00196
00197 buildstate->haveDead = true;
00198 _bt_spool(itup, buildstate->spool2);
00199 }
00200
00201 buildstate->indtuples += 1;
00202
00203 pfree(itup);
00204 }
00205
00206
00207
00208
00209 Datum
00210 btbuildempty(PG_FUNCTION_ARGS)
00211 {
00212 Relation index = (Relation) PG_GETARG_POINTER(0);
00213 Page metapage;
00214
00215
00216 metapage = (Page) palloc(BLCKSZ);
00217 _bt_initmetapage(metapage, P_NONE, 0);
00218
00219
00220 PageSetChecksumInplace(metapage, BTREE_METAPAGE);
00221 smgrwrite(index->rd_smgr, INIT_FORKNUM, BTREE_METAPAGE,
00222 (char *) metapage, true);
00223 if (XLogIsNeeded())
00224 log_newpage(&index->rd_smgr->smgr_rnode.node, INIT_FORKNUM,
00225 BTREE_METAPAGE, metapage);
00226
00227
00228
00229
00230
00231
00232 smgrimmedsync(index->rd_smgr, INIT_FORKNUM);
00233
00234 PG_RETURN_VOID();
00235 }
00236
00237
00238
00239
00240
00241
00242
00243 Datum
00244 btinsert(PG_FUNCTION_ARGS)
00245 {
00246 Relation rel = (Relation) PG_GETARG_POINTER(0);
00247 Datum *values = (Datum *) PG_GETARG_POINTER(1);
00248 bool *isnull = (bool *) PG_GETARG_POINTER(2);
00249 ItemPointer ht_ctid = (ItemPointer) PG_GETARG_POINTER(3);
00250 Relation heapRel = (Relation) PG_GETARG_POINTER(4);
00251 IndexUniqueCheck checkUnique = (IndexUniqueCheck) PG_GETARG_INT32(5);
00252 bool result;
00253 IndexTuple itup;
00254
00255
00256 itup = index_form_tuple(RelationGetDescr(rel), values, isnull);
00257 itup->t_tid = *ht_ctid;
00258
00259 result = _bt_doinsert(rel, itup, checkUnique, heapRel);
00260
00261 pfree(itup);
00262
00263 PG_RETURN_BOOL(result);
00264 }
00265
00266
00267
00268
00269 Datum
00270 btgettuple(PG_FUNCTION_ARGS)
00271 {
00272 IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
00273 ScanDirection dir = (ScanDirection) PG_GETARG_INT32(1);
00274 BTScanOpaque so = (BTScanOpaque) scan->opaque;
00275 bool res;
00276
00277
00278 scan->xs_recheck = false;
00279
00280
00281
00282
00283
00284
00285 if (so->numArrayKeys && !BTScanPosIsValid(so->currPos))
00286 {
00287
00288 if (so->numArrayKeys < 0)
00289 PG_RETURN_BOOL(false);
00290
00291 _bt_start_array_keys(scan, dir);
00292 }
00293
00294
00295 do
00296 {
00297
00298
00299
00300
00301
00302 if (!BTScanPosIsValid(so->currPos))
00303 res = _bt_first(scan, dir);
00304 else
00305 {
00306
00307
00308
00309 if (scan->kill_prior_tuple)
00310 {
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320 if (so->killedItems == NULL)
00321 so->killedItems = (int *)
00322 palloc(MaxIndexTuplesPerPage * sizeof(int));
00323 if (so->numKilled < MaxIndexTuplesPerPage)
00324 so->killedItems[so->numKilled++] = so->currPos.itemIndex;
00325 }
00326
00327
00328
00329
00330 res = _bt_next(scan, dir);
00331 }
00332
00333
00334 if (res)
00335 break;
00336
00337 } while (so->numArrayKeys && _bt_advance_array_keys(scan, dir));
00338
00339 PG_RETURN_BOOL(res);
00340 }
00341
00342
00343
00344
00345 Datum
00346 btgetbitmap(PG_FUNCTION_ARGS)
00347 {
00348 IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
00349 TIDBitmap *tbm = (TIDBitmap *) PG_GETARG_POINTER(1);
00350 BTScanOpaque so = (BTScanOpaque) scan->opaque;
00351 int64 ntids = 0;
00352 ItemPointer heapTid;
00353
00354
00355
00356
00357 if (so->numArrayKeys)
00358 {
00359
00360 if (so->numArrayKeys < 0)
00361 PG_RETURN_INT64(ntids);
00362
00363 _bt_start_array_keys(scan, ForwardScanDirection);
00364 }
00365
00366
00367 do
00368 {
00369
00370 if (_bt_first(scan, ForwardScanDirection))
00371 {
00372
00373 heapTid = &scan->xs_ctup.t_self;
00374 tbm_add_tuples(tbm, heapTid, 1, false);
00375 ntids++;
00376
00377 for (;;)
00378 {
00379
00380
00381
00382
00383 if (++so->currPos.itemIndex > so->currPos.lastItem)
00384 {
00385
00386 if (!_bt_next(scan, ForwardScanDirection))
00387 break;
00388 }
00389
00390
00391 heapTid = &so->currPos.items[so->currPos.itemIndex].heapTid;
00392 tbm_add_tuples(tbm, heapTid, 1, false);
00393 ntids++;
00394 }
00395 }
00396
00397 } while (so->numArrayKeys && _bt_advance_array_keys(scan, ForwardScanDirection));
00398
00399 PG_RETURN_INT64(ntids);
00400 }
00401
00402
00403
00404
00405 Datum
00406 btbeginscan(PG_FUNCTION_ARGS)
00407 {
00408 Relation rel = (Relation) PG_GETARG_POINTER(0);
00409 int nkeys = PG_GETARG_INT32(1);
00410 int norderbys = PG_GETARG_INT32(2);
00411 IndexScanDesc scan;
00412 BTScanOpaque so;
00413
00414
00415 Assert(norderbys == 0);
00416
00417
00418 scan = RelationGetIndexScan(rel, nkeys, norderbys);
00419
00420
00421 so = (BTScanOpaque) palloc(sizeof(BTScanOpaqueData));
00422 so->currPos.buf = so->markPos.buf = InvalidBuffer;
00423 if (scan->numberOfKeys > 0)
00424 so->keyData = (ScanKey) palloc(scan->numberOfKeys * sizeof(ScanKeyData));
00425 else
00426 so->keyData = NULL;
00427
00428 so->arrayKeyData = NULL;
00429 so->numArrayKeys = 0;
00430 so->arrayKeys = NULL;
00431 so->arrayContext = NULL;
00432
00433 so->killedItems = NULL;
00434 so->numKilled = 0;
00435
00436
00437
00438
00439
00440
00441 so->currTuples = so->markTuples = NULL;
00442 so->currPos.nextTupleOffset = 0;
00443 so->markPos.nextTupleOffset = 0;
00444
00445 scan->xs_itupdesc = RelationGetDescr(rel);
00446
00447 scan->opaque = so;
00448
00449 PG_RETURN_POINTER(scan);
00450 }
00451
00452
00453
00454
00455 Datum
00456 btrescan(PG_FUNCTION_ARGS)
00457 {
00458 IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
00459 ScanKey scankey = (ScanKey) PG_GETARG_POINTER(1);
00460
00461
00462 BTScanOpaque so = (BTScanOpaque) scan->opaque;
00463
00464
00465 if (BTScanPosIsValid(so->currPos))
00466 {
00467
00468 if (so->numKilled > 0)
00469 _bt_killitems(scan, false);
00470 ReleaseBuffer(so->currPos.buf);
00471 so->currPos.buf = InvalidBuffer;
00472 }
00473
00474 if (BTScanPosIsValid(so->markPos))
00475 {
00476 ReleaseBuffer(so->markPos.buf);
00477 so->markPos.buf = InvalidBuffer;
00478 }
00479 so->markItemIndex = -1;
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497 if (scan->xs_want_itup && so->currTuples == NULL)
00498 {
00499 so->currTuples = (char *) palloc(BLCKSZ * 2);
00500 so->markTuples = so->currTuples + BLCKSZ;
00501 }
00502
00503
00504
00505
00506
00507 if (scankey && scan->numberOfKeys > 0)
00508 memmove(scan->keyData,
00509 scankey,
00510 scan->numberOfKeys * sizeof(ScanKeyData));
00511 so->numberOfKeys = 0;
00512
00513
00514 _bt_preprocess_array_keys(scan);
00515
00516 PG_RETURN_VOID();
00517 }
00518
00519
00520
00521
00522 Datum
00523 btendscan(PG_FUNCTION_ARGS)
00524 {
00525 IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
00526 BTScanOpaque so = (BTScanOpaque) scan->opaque;
00527
00528
00529 if (BTScanPosIsValid(so->currPos))
00530 {
00531
00532 if (so->numKilled > 0)
00533 _bt_killitems(scan, false);
00534 ReleaseBuffer(so->currPos.buf);
00535 so->currPos.buf = InvalidBuffer;
00536 }
00537
00538 if (BTScanPosIsValid(so->markPos))
00539 {
00540 ReleaseBuffer(so->markPos.buf);
00541 so->markPos.buf = InvalidBuffer;
00542 }
00543 so->markItemIndex = -1;
00544
00545
00546 if (so->keyData != NULL)
00547 pfree(so->keyData);
00548
00549 if (so->arrayContext != NULL)
00550 MemoryContextDelete(so->arrayContext);
00551 if (so->killedItems != NULL)
00552 pfree(so->killedItems);
00553 if (so->currTuples != NULL)
00554 pfree(so->currTuples);
00555
00556 pfree(so);
00557
00558 PG_RETURN_VOID();
00559 }
00560
00561
00562
00563
00564 Datum
00565 btmarkpos(PG_FUNCTION_ARGS)
00566 {
00567 IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
00568 BTScanOpaque so = (BTScanOpaque) scan->opaque;
00569
00570
00571 if (BTScanPosIsValid(so->markPos))
00572 {
00573 ReleaseBuffer(so->markPos.buf);
00574 so->markPos.buf = InvalidBuffer;
00575 }
00576
00577
00578
00579
00580
00581
00582
00583 if (BTScanPosIsValid(so->currPos))
00584 so->markItemIndex = so->currPos.itemIndex;
00585 else
00586 so->markItemIndex = -1;
00587
00588
00589 if (so->numArrayKeys)
00590 _bt_mark_array_keys(scan);
00591
00592 PG_RETURN_VOID();
00593 }
00594
00595
00596
00597
00598 Datum
00599 btrestrpos(PG_FUNCTION_ARGS)
00600 {
00601 IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
00602 BTScanOpaque so = (BTScanOpaque) scan->opaque;
00603
00604
00605 if (so->numArrayKeys)
00606 _bt_restore_array_keys(scan);
00607
00608 if (so->markItemIndex >= 0)
00609 {
00610
00611
00612
00613
00614 so->currPos.itemIndex = so->markItemIndex;
00615 }
00616 else
00617 {
00618
00619 if (BTScanPosIsValid(so->currPos))
00620 {
00621
00622 if (so->numKilled > 0 &&
00623 so->currPos.buf != so->markPos.buf)
00624 _bt_killitems(scan, false);
00625 ReleaseBuffer(so->currPos.buf);
00626 so->currPos.buf = InvalidBuffer;
00627 }
00628
00629 if (BTScanPosIsValid(so->markPos))
00630 {
00631
00632 IncrBufferRefCount(so->markPos.buf);
00633 memcpy(&so->currPos, &so->markPos,
00634 offsetof(BTScanPosData, items[1]) +
00635 so->markPos.lastItem * sizeof(BTScanPosItem));
00636 if (so->currTuples)
00637 memcpy(so->currTuples, so->markTuples,
00638 so->markPos.nextTupleOffset);
00639 }
00640 }
00641
00642 PG_RETURN_VOID();
00643 }
00644
00645
00646
00647
00648
00649
00650
00651
00652 Datum
00653 btbulkdelete(PG_FUNCTION_ARGS)
00654 {
00655 IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0);
00656 IndexBulkDeleteResult *volatile stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1);
00657 IndexBulkDeleteCallback callback = (IndexBulkDeleteCallback) PG_GETARG_POINTER(2);
00658 void *callback_state = (void *) PG_GETARG_POINTER(3);
00659 Relation rel = info->index;
00660 BTCycleId cycleid;
00661
00662
00663 if (stats == NULL)
00664 stats = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult));
00665
00666
00667
00668 PG_ENSURE_ERROR_CLEANUP(_bt_end_vacuum_callback, PointerGetDatum(rel));
00669 {
00670 cycleid = _bt_start_vacuum(rel);
00671
00672 btvacuumscan(info, stats, callback, callback_state, cycleid);
00673 }
00674 PG_END_ENSURE_ERROR_CLEANUP(_bt_end_vacuum_callback, PointerGetDatum(rel));
00675 _bt_end_vacuum(rel);
00676
00677 PG_RETURN_POINTER(stats);
00678 }
00679
00680
00681
00682
00683
00684
00685 Datum
00686 btvacuumcleanup(PG_FUNCTION_ARGS)
00687 {
00688 IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0);
00689 IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1);
00690
00691
00692 if (info->analyze_only)
00693 PG_RETURN_POINTER(stats);
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704 if (stats == NULL)
00705 {
00706 stats = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult));
00707 btvacuumscan(info, stats, NULL, NULL, 0);
00708 }
00709
00710
00711 IndexFreeSpaceMapVacuum(info->index);
00712
00713
00714
00715
00716
00717
00718
00719 if (!info->estimated_count)
00720 {
00721 if (stats->num_index_tuples > info->num_heap_tuples)
00722 stats->num_index_tuples = info->num_heap_tuples;
00723 }
00724
00725 PG_RETURN_POINTER(stats);
00726 }
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740 static void
00741 btvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
00742 IndexBulkDeleteCallback callback, void *callback_state,
00743 BTCycleId cycleid)
00744 {
00745 Relation rel = info->index;
00746 BTVacState vstate;
00747 BlockNumber num_pages;
00748 BlockNumber blkno;
00749 bool needLock;
00750
00751
00752
00753
00754
00755 stats->estimated_count = false;
00756 stats->num_index_tuples = 0;
00757 stats->pages_deleted = 0;
00758
00759
00760 vstate.info = info;
00761 vstate.stats = stats;
00762 vstate.callback = callback;
00763 vstate.callback_state = callback_state;
00764 vstate.cycleid = cycleid;
00765 vstate.lastBlockVacuumed = BTREE_METAPAGE;
00766 vstate.lastUsedPage = BTREE_METAPAGE;
00767 vstate.totFreePages = 0;
00768
00769
00770 vstate.pagedelcontext = AllocSetContextCreate(CurrentMemoryContext,
00771 "_bt_pagedel",
00772 ALLOCSET_DEFAULT_MINSIZE,
00773 ALLOCSET_DEFAULT_INITSIZE,
00774 ALLOCSET_DEFAULT_MAXSIZE);
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799 needLock = !RELATION_IS_LOCAL(rel);
00800
00801 blkno = BTREE_METAPAGE + 1;
00802 for (;;)
00803 {
00804
00805 if (needLock)
00806 LockRelationForExtension(rel, ExclusiveLock);
00807 num_pages = RelationGetNumberOfBlocks(rel);
00808 if (needLock)
00809 UnlockRelationForExtension(rel, ExclusiveLock);
00810
00811
00812 if (blkno >= num_pages)
00813 break;
00814
00815 for (; blkno < num_pages; blkno++)
00816 {
00817 btvacuumpage(&vstate, blkno, blkno);
00818 }
00819 }
00820
00821
00822
00823
00824
00825
00826
00827
00828
00829 if (XLogStandbyInfoActive() &&
00830 num_pages > 1 && vstate.lastBlockVacuumed < (num_pages - 1))
00831 {
00832 Buffer buf;
00833
00834
00835
00836
00837
00838
00839
00840 buf = ReadBufferExtended(rel, MAIN_FORKNUM, num_pages - 1, RBM_NORMAL,
00841 info->strategy);
00842 LockBufferForCleanup(buf);
00843 _bt_delitems_vacuum(rel, buf, NULL, 0, vstate.lastBlockVacuumed);
00844 _bt_relbuf(rel, buf);
00845 }
00846
00847 MemoryContextDelete(vstate.pagedelcontext);
00848
00849
00850 stats->num_pages = num_pages;
00851 stats->pages_free = vstate.totFreePages;
00852 }
00853
00854
00855
00856
00857
00858
00859
00860
00861
00862
00863
00864
00865 static void
00866 btvacuumpage(BTVacState *vstate, BlockNumber blkno, BlockNumber orig_blkno)
00867 {
00868 IndexVacuumInfo *info = vstate->info;
00869 IndexBulkDeleteResult *stats = vstate->stats;
00870 IndexBulkDeleteCallback callback = vstate->callback;
00871 void *callback_state = vstate->callback_state;
00872 Relation rel = info->index;
00873 bool delete_now;
00874 BlockNumber recurse_to;
00875 Buffer buf;
00876 Page page;
00877 BTPageOpaque opaque;
00878
00879 restart:
00880 delete_now = false;
00881 recurse_to = P_NONE;
00882
00883
00884 vacuum_delay_point();
00885
00886
00887
00888
00889
00890
00891
00892 buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL,
00893 info->strategy);
00894 LockBuffer(buf, BT_READ);
00895 page = BufferGetPage(buf);
00896 opaque = (BTPageOpaque) PageGetSpecialPointer(page);
00897 if (!PageIsNew(page))
00898 _bt_checkpage(rel, buf);
00899
00900
00901
00902
00903
00904
00905 if (blkno != orig_blkno)
00906 {
00907 if (_bt_page_recyclable(page) ||
00908 P_IGNORE(opaque) ||
00909 !P_ISLEAF(opaque) ||
00910 opaque->btpo_cycleid != vstate->cycleid)
00911 {
00912 _bt_relbuf(rel, buf);
00913 return;
00914 }
00915 }
00916
00917
00918 if (!_bt_page_recyclable(page) && vstate->lastUsedPage < blkno)
00919 vstate->lastUsedPage = blkno;
00920
00921
00922 if (_bt_page_recyclable(page))
00923 {
00924
00925 RecordFreeIndexPage(rel, blkno);
00926 vstate->totFreePages++;
00927 stats->pages_deleted++;
00928 }
00929 else if (P_ISDELETED(opaque))
00930 {
00931
00932 stats->pages_deleted++;
00933 }
00934 else if (P_ISHALFDEAD(opaque))
00935 {
00936
00937 delete_now = true;
00938 }
00939 else if (P_ISLEAF(opaque))
00940 {
00941 OffsetNumber deletable[MaxOffsetNumber];
00942 int ndeletable;
00943 OffsetNumber offnum,
00944 minoff,
00945 maxoff;
00946
00947
00948
00949
00950
00951
00952
00953 LockBuffer(buf, BUFFER_LOCK_UNLOCK);
00954 LockBufferForCleanup(buf);
00955
00956
00957
00958
00959
00960
00961
00962
00963 if (vstate->cycleid != 0 &&
00964 opaque->btpo_cycleid == vstate->cycleid &&
00965 !(opaque->btpo_flags & BTP_SPLIT_END) &&
00966 !P_RIGHTMOST(opaque) &&
00967 opaque->btpo_next < orig_blkno)
00968 recurse_to = opaque->btpo_next;
00969
00970
00971
00972
00973
00974 ndeletable = 0;
00975 minoff = P_FIRSTDATAKEY(opaque);
00976 maxoff = PageGetMaxOffsetNumber(page);
00977 if (callback)
00978 {
00979 for (offnum = minoff;
00980 offnum <= maxoff;
00981 offnum = OffsetNumberNext(offnum))
00982 {
00983 IndexTuple itup;
00984 ItemPointer htup;
00985
00986 itup = (IndexTuple) PageGetItem(page,
00987 PageGetItemId(page, offnum));
00988 htup = &(itup->t_tid);
00989
00990
00991
00992
00993
00994
00995
00996
00997
00998
00999
01000
01001
01002
01003
01004
01005
01006
01007
01008
01009
01010
01011 if (callback(htup, callback_state))
01012 deletable[ndeletable++] = offnum;
01013 }
01014 }
01015
01016
01017
01018
01019
01020 if (ndeletable > 0)
01021 {
01022 BlockNumber lastBlockVacuumed = BufferGetBlockNumber(buf);
01023
01024 _bt_delitems_vacuum(rel, buf, deletable, ndeletable,
01025 vstate->lastBlockVacuumed);
01026
01027
01028
01029
01030
01031
01032
01033 if (lastBlockVacuumed > vstate->lastBlockVacuumed)
01034 vstate->lastBlockVacuumed = lastBlockVacuumed;
01035
01036 stats->tuples_removed += ndeletable;
01037
01038 maxoff = PageGetMaxOffsetNumber(page);
01039 }
01040 else
01041 {
01042
01043
01044
01045
01046
01047
01048
01049
01050
01051 if (vstate->cycleid != 0 &&
01052 opaque->btpo_cycleid == vstate->cycleid)
01053 {
01054 opaque->btpo_cycleid = 0;
01055 MarkBufferDirtyHint(buf);
01056 }
01057 }
01058
01059
01060
01061
01062
01063
01064
01065 if (minoff > maxoff)
01066 delete_now = (blkno == orig_blkno);
01067 else
01068 stats->num_index_tuples += maxoff - minoff + 1;
01069 }
01070
01071 if (delete_now)
01072 {
01073 MemoryContext oldcontext;
01074 int ndel;
01075
01076
01077 MemoryContextReset(vstate->pagedelcontext);
01078 oldcontext = MemoryContextSwitchTo(vstate->pagedelcontext);
01079
01080 ndel = _bt_pagedel(rel, buf, NULL);
01081
01082
01083 if (ndel)
01084 stats->pages_deleted++;
01085
01086 MemoryContextSwitchTo(oldcontext);
01087
01088 }
01089 else
01090 _bt_relbuf(rel, buf);
01091
01092
01093
01094
01095
01096
01097
01098
01099 if (recurse_to != P_NONE)
01100 {
01101 blkno = recurse_to;
01102 goto restart;
01103 }
01104 }
01105
01106
01107
01108
01109
01110
01111 Datum
01112 btcanreturn(PG_FUNCTION_ARGS)
01113 {
01114 PG_RETURN_BOOL(true);
01115 }