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 #include "postgres.h"
00040
00041 #include <limits.h>
00042
00043 #include "access/htup_details.h"
00044 #include "nodes/bitmapset.h"
00045 #include "nodes/tidbitmap.h"
00046 #include "utils/hsearch.h"
00047
00048
00049
00050
00051
00052
00053
00054 #define MAX_TUPLES_PER_PAGE MaxHeapTuplesPerPage
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071 #define PAGES_PER_CHUNK (BLCKSZ / 32)
00072
00073
00074
00075 #define WORDNUM(x) ((x) / BITS_PER_BITMAPWORD)
00076 #define BITNUM(x) ((x) % BITS_PER_BITMAPWORD)
00077
00078
00079 #define WORDS_PER_PAGE ((MAX_TUPLES_PER_PAGE - 1) / BITS_PER_BITMAPWORD + 1)
00080
00081 #define WORDS_PER_CHUNK ((PAGES_PER_CHUNK - 1) / BITS_PER_BITMAPWORD + 1)
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097 typedef struct PagetableEntry
00098 {
00099 BlockNumber blockno;
00100 bool ischunk;
00101 bool recheck;
00102 bitmapword words[Max(WORDS_PER_PAGE, WORDS_PER_CHUNK)];
00103 } PagetableEntry;
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116 typedef enum
00117 {
00118 TBM_EMPTY,
00119 TBM_ONE_PAGE,
00120 TBM_HASH
00121 } TBMStatus;
00122
00123
00124
00125
00126 struct TIDBitmap
00127 {
00128 NodeTag type;
00129 MemoryContext mcxt;
00130 TBMStatus status;
00131 HTAB *pagetable;
00132 int nentries;
00133 int maxentries;
00134 int npages;
00135 int nchunks;
00136 bool iterating;
00137 PagetableEntry entry1;
00138
00139 PagetableEntry **spages;
00140 PagetableEntry **schunks;
00141 };
00142
00143
00144
00145
00146
00147
00148
00149 struct TBMIterator
00150 {
00151 TIDBitmap *tbm;
00152 int spageptr;
00153 int schunkptr;
00154 int schunkbit;
00155 TBMIterateResult output;
00156 };
00157
00158
00159
00160 static void tbm_union_page(TIDBitmap *a, const PagetableEntry *bpage);
00161 static bool tbm_intersect_page(TIDBitmap *a, PagetableEntry *apage,
00162 const TIDBitmap *b);
00163 static const PagetableEntry *tbm_find_pageentry(const TIDBitmap *tbm,
00164 BlockNumber pageno);
00165 static PagetableEntry *tbm_get_pageentry(TIDBitmap *tbm, BlockNumber pageno);
00166 static bool tbm_page_is_lossy(const TIDBitmap *tbm, BlockNumber pageno);
00167 static void tbm_mark_page_lossy(TIDBitmap *tbm, BlockNumber pageno);
00168 static void tbm_lossify(TIDBitmap *tbm);
00169 static int tbm_comparator(const void *left, const void *right);
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179 TIDBitmap *
00180 tbm_create(long maxbytes)
00181 {
00182 TIDBitmap *tbm;
00183 long nbuckets;
00184
00185
00186 tbm = makeNode(TIDBitmap);
00187
00188 tbm->mcxt = CurrentMemoryContext;
00189 tbm->status = TBM_EMPTY;
00190
00191
00192
00193
00194
00195
00196
00197
00198 nbuckets = maxbytes /
00199 (MAXALIGN(sizeof(HASHELEMENT)) + MAXALIGN(sizeof(PagetableEntry))
00200 + sizeof(Pointer) + sizeof(Pointer));
00201 nbuckets = Min(nbuckets, INT_MAX - 1);
00202 nbuckets = Max(nbuckets, 16);
00203 tbm->maxentries = (int) nbuckets;
00204
00205 return tbm;
00206 }
00207
00208
00209
00210
00211
00212 static void
00213 tbm_create_pagetable(TIDBitmap *tbm)
00214 {
00215 HASHCTL hash_ctl;
00216
00217 Assert(tbm->status != TBM_HASH);
00218 Assert(tbm->pagetable == NULL);
00219
00220
00221 MemSet(&hash_ctl, 0, sizeof(hash_ctl));
00222 hash_ctl.keysize = sizeof(BlockNumber);
00223 hash_ctl.entrysize = sizeof(PagetableEntry);
00224 hash_ctl.hash = tag_hash;
00225 hash_ctl.hcxt = tbm->mcxt;
00226 tbm->pagetable = hash_create("TIDBitmap",
00227 128,
00228 &hash_ctl,
00229 HASH_ELEM | HASH_FUNCTION | HASH_CONTEXT);
00230
00231
00232 if (tbm->status == TBM_ONE_PAGE)
00233 {
00234 PagetableEntry *page;
00235 bool found;
00236
00237 page = (PagetableEntry *) hash_search(tbm->pagetable,
00238 (void *) &tbm->entry1.blockno,
00239 HASH_ENTER, &found);
00240 Assert(!found);
00241 memcpy(page, &tbm->entry1, sizeof(PagetableEntry));
00242 }
00243
00244 tbm->status = TBM_HASH;
00245 }
00246
00247
00248
00249
00250 void
00251 tbm_free(TIDBitmap *tbm)
00252 {
00253 if (tbm->pagetable)
00254 hash_destroy(tbm->pagetable);
00255 if (tbm->spages)
00256 pfree(tbm->spages);
00257 if (tbm->schunks)
00258 pfree(tbm->schunks);
00259 pfree(tbm);
00260 }
00261
00262
00263
00264
00265
00266
00267
00268 void
00269 tbm_add_tuples(TIDBitmap *tbm, const ItemPointer tids, int ntids,
00270 bool recheck)
00271 {
00272 int i;
00273
00274 Assert(!tbm->iterating);
00275 for (i = 0; i < ntids; i++)
00276 {
00277 BlockNumber blk = ItemPointerGetBlockNumber(tids + i);
00278 OffsetNumber off = ItemPointerGetOffsetNumber(tids + i);
00279 PagetableEntry *page;
00280 int wordnum,
00281 bitnum;
00282
00283
00284 if (off < 1 || off > MAX_TUPLES_PER_PAGE)
00285 elog(ERROR, "tuple offset out of range: %u", off);
00286
00287 if (tbm_page_is_lossy(tbm, blk))
00288 continue;
00289
00290 page = tbm_get_pageentry(tbm, blk);
00291
00292 if (page->ischunk)
00293 {
00294
00295 wordnum = bitnum = 0;
00296 }
00297 else
00298 {
00299
00300 wordnum = WORDNUM(off - 1);
00301 bitnum = BITNUM(off - 1);
00302 }
00303 page->words[wordnum] |= ((bitmapword) 1 << bitnum);
00304 page->recheck |= recheck;
00305
00306 if (tbm->nentries > tbm->maxentries)
00307 tbm_lossify(tbm);
00308 }
00309 }
00310
00311
00312
00313
00314
00315
00316
00317 void
00318 tbm_add_page(TIDBitmap *tbm, BlockNumber pageno)
00319 {
00320
00321 tbm_mark_page_lossy(tbm, pageno);
00322
00323 if (tbm->nentries > tbm->maxentries)
00324 tbm_lossify(tbm);
00325 }
00326
00327
00328
00329
00330
00331
00332 void
00333 tbm_union(TIDBitmap *a, const TIDBitmap *b)
00334 {
00335 Assert(!a->iterating);
00336
00337 if (b->nentries == 0)
00338 return;
00339
00340 if (b->status == TBM_ONE_PAGE)
00341 tbm_union_page(a, &b->entry1);
00342 else
00343 {
00344 HASH_SEQ_STATUS status;
00345 PagetableEntry *bpage;
00346
00347 Assert(b->status == TBM_HASH);
00348 hash_seq_init(&status, b->pagetable);
00349 while ((bpage = (PagetableEntry *) hash_seq_search(&status)) != NULL)
00350 tbm_union_page(a, bpage);
00351 }
00352 }
00353
00354
00355 static void
00356 tbm_union_page(TIDBitmap *a, const PagetableEntry *bpage)
00357 {
00358 PagetableEntry *apage;
00359 int wordnum;
00360
00361 if (bpage->ischunk)
00362 {
00363
00364 for (wordnum = 0; wordnum < WORDS_PER_PAGE; wordnum++)
00365 {
00366 bitmapword w = bpage->words[wordnum];
00367
00368 if (w != 0)
00369 {
00370 BlockNumber pg;
00371
00372 pg = bpage->blockno + (wordnum * BITS_PER_BITMAPWORD);
00373 while (w != 0)
00374 {
00375 if (w & 1)
00376 tbm_mark_page_lossy(a, pg);
00377 pg++;
00378 w >>= 1;
00379 }
00380 }
00381 }
00382 }
00383 else if (tbm_page_is_lossy(a, bpage->blockno))
00384 {
00385
00386 return;
00387 }
00388 else
00389 {
00390 apage = tbm_get_pageentry(a, bpage->blockno);
00391 if (apage->ischunk)
00392 {
00393
00394 apage->words[0] |= ((bitmapword) 1 << 0);
00395 }
00396 else
00397 {
00398
00399 for (wordnum = 0; wordnum < WORDS_PER_PAGE; wordnum++)
00400 apage->words[wordnum] |= bpage->words[wordnum];
00401 apage->recheck |= bpage->recheck;
00402 }
00403 }
00404
00405 if (a->nentries > a->maxentries)
00406 tbm_lossify(a);
00407 }
00408
00409
00410
00411
00412
00413
00414 void
00415 tbm_intersect(TIDBitmap *a, const TIDBitmap *b)
00416 {
00417 Assert(!a->iterating);
00418
00419 if (a->nentries == 0)
00420 return;
00421
00422 if (a->status == TBM_ONE_PAGE)
00423 {
00424 if (tbm_intersect_page(a, &a->entry1, b))
00425 {
00426
00427 Assert(!a->entry1.ischunk);
00428 a->npages--;
00429 a->nentries--;
00430 Assert(a->nentries == 0);
00431 a->status = TBM_EMPTY;
00432 }
00433 }
00434 else
00435 {
00436 HASH_SEQ_STATUS status;
00437 PagetableEntry *apage;
00438
00439 Assert(a->status == TBM_HASH);
00440 hash_seq_init(&status, a->pagetable);
00441 while ((apage = (PagetableEntry *) hash_seq_search(&status)) != NULL)
00442 {
00443 if (tbm_intersect_page(a, apage, b))
00444 {
00445
00446 if (apage->ischunk)
00447 a->nchunks--;
00448 else
00449 a->npages--;
00450 a->nentries--;
00451 if (hash_search(a->pagetable,
00452 (void *) &apage->blockno,
00453 HASH_REMOVE, NULL) == NULL)
00454 elog(ERROR, "hash table corrupted");
00455 }
00456 }
00457 }
00458 }
00459
00460
00461
00462
00463
00464
00465 static bool
00466 tbm_intersect_page(TIDBitmap *a, PagetableEntry *apage, const TIDBitmap *b)
00467 {
00468 const PagetableEntry *bpage;
00469 int wordnum;
00470
00471 if (apage->ischunk)
00472 {
00473
00474 bool candelete = true;
00475
00476 for (wordnum = 0; wordnum < WORDS_PER_PAGE; wordnum++)
00477 {
00478 bitmapword w = apage->words[wordnum];
00479
00480 if (w != 0)
00481 {
00482 bitmapword neww = w;
00483 BlockNumber pg;
00484 int bitnum;
00485
00486 pg = apage->blockno + (wordnum * BITS_PER_BITMAPWORD);
00487 bitnum = 0;
00488 while (w != 0)
00489 {
00490 if (w & 1)
00491 {
00492 if (!tbm_page_is_lossy(b, pg) &&
00493 tbm_find_pageentry(b, pg) == NULL)
00494 {
00495
00496 neww &= ~((bitmapword) 1 << bitnum);
00497 }
00498 }
00499 pg++;
00500 bitnum++;
00501 w >>= 1;
00502 }
00503 apage->words[wordnum] = neww;
00504 if (neww != 0)
00505 candelete = false;
00506 }
00507 }
00508 return candelete;
00509 }
00510 else if (tbm_page_is_lossy(b, apage->blockno))
00511 {
00512
00513
00514
00515
00516
00517
00518 apage->recheck = true;
00519 return false;
00520 }
00521 else
00522 {
00523 bool candelete = true;
00524
00525 bpage = tbm_find_pageentry(b, apage->blockno);
00526 if (bpage != NULL)
00527 {
00528
00529 Assert(!bpage->ischunk);
00530 for (wordnum = 0; wordnum < WORDS_PER_PAGE; wordnum++)
00531 {
00532 apage->words[wordnum] &= bpage->words[wordnum];
00533 if (apage->words[wordnum] != 0)
00534 candelete = false;
00535 }
00536 apage->recheck |= bpage->recheck;
00537 }
00538
00539 return candelete;
00540 }
00541 }
00542
00543
00544
00545
00546 bool
00547 tbm_is_empty(const TIDBitmap *tbm)
00548 {
00549 return (tbm->nentries == 0);
00550 }
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565 TBMIterator *
00566 tbm_begin_iterate(TIDBitmap *tbm)
00567 {
00568 TBMIterator *iterator;
00569
00570
00571
00572
00573
00574 iterator = (TBMIterator *) palloc(sizeof(TBMIterator) +
00575 MAX_TUPLES_PER_PAGE * sizeof(OffsetNumber));
00576 iterator->tbm = tbm;
00577
00578
00579
00580
00581 iterator->spageptr = 0;
00582 iterator->schunkptr = 0;
00583 iterator->schunkbit = 0;
00584
00585
00586
00587
00588
00589
00590
00591 if (tbm->status == TBM_HASH && !tbm->iterating)
00592 {
00593 HASH_SEQ_STATUS status;
00594 PagetableEntry *page;
00595 int npages;
00596 int nchunks;
00597
00598 if (!tbm->spages && tbm->npages > 0)
00599 tbm->spages = (PagetableEntry **)
00600 MemoryContextAlloc(tbm->mcxt,
00601 tbm->npages * sizeof(PagetableEntry *));
00602 if (!tbm->schunks && tbm->nchunks > 0)
00603 tbm->schunks = (PagetableEntry **)
00604 MemoryContextAlloc(tbm->mcxt,
00605 tbm->nchunks * sizeof(PagetableEntry *));
00606
00607 hash_seq_init(&status, tbm->pagetable);
00608 npages = nchunks = 0;
00609 while ((page = (PagetableEntry *) hash_seq_search(&status)) != NULL)
00610 {
00611 if (page->ischunk)
00612 tbm->schunks[nchunks++] = page;
00613 else
00614 tbm->spages[npages++] = page;
00615 }
00616 Assert(npages == tbm->npages);
00617 Assert(nchunks == tbm->nchunks);
00618 if (npages > 1)
00619 qsort(tbm->spages, npages, sizeof(PagetableEntry *),
00620 tbm_comparator);
00621 if (nchunks > 1)
00622 qsort(tbm->schunks, nchunks, sizeof(PagetableEntry *),
00623 tbm_comparator);
00624 }
00625
00626 tbm->iterating = true;
00627
00628 return iterator;
00629 }
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643 TBMIterateResult *
00644 tbm_iterate(TBMIterator *iterator)
00645 {
00646 TIDBitmap *tbm = iterator->tbm;
00647 TBMIterateResult *output = &(iterator->output);
00648
00649 Assert(tbm->iterating);
00650
00651
00652
00653
00654
00655 while (iterator->schunkptr < tbm->nchunks)
00656 {
00657 PagetableEntry *chunk = tbm->schunks[iterator->schunkptr];
00658 int schunkbit = iterator->schunkbit;
00659
00660 while (schunkbit < PAGES_PER_CHUNK)
00661 {
00662 int wordnum = WORDNUM(schunkbit);
00663 int bitnum = BITNUM(schunkbit);
00664
00665 if ((chunk->words[wordnum] & ((bitmapword) 1 << bitnum)) != 0)
00666 break;
00667 schunkbit++;
00668 }
00669 if (schunkbit < PAGES_PER_CHUNK)
00670 {
00671 iterator->schunkbit = schunkbit;
00672 break;
00673 }
00674
00675 iterator->schunkptr++;
00676 iterator->schunkbit = 0;
00677 }
00678
00679
00680
00681
00682
00683 if (iterator->schunkptr < tbm->nchunks)
00684 {
00685 PagetableEntry *chunk = tbm->schunks[iterator->schunkptr];
00686 BlockNumber chunk_blockno;
00687
00688 chunk_blockno = chunk->blockno + iterator->schunkbit;
00689 if (iterator->spageptr >= tbm->npages ||
00690 chunk_blockno < tbm->spages[iterator->spageptr]->blockno)
00691 {
00692
00693 output->blockno = chunk_blockno;
00694 output->ntuples = -1;
00695 output->recheck = true;
00696 iterator->schunkbit++;
00697 return output;
00698 }
00699 }
00700
00701 if (iterator->spageptr < tbm->npages)
00702 {
00703 PagetableEntry *page;
00704 int ntuples;
00705 int wordnum;
00706
00707
00708 if (tbm->status == TBM_ONE_PAGE)
00709 page = &tbm->entry1;
00710 else
00711 page = tbm->spages[iterator->spageptr];
00712
00713
00714 ntuples = 0;
00715 for (wordnum = 0; wordnum < WORDS_PER_PAGE; wordnum++)
00716 {
00717 bitmapword w = page->words[wordnum];
00718
00719 if (w != 0)
00720 {
00721 int off = wordnum * BITS_PER_BITMAPWORD + 1;
00722
00723 while (w != 0)
00724 {
00725 if (w & 1)
00726 output->offsets[ntuples++] = (OffsetNumber) off;
00727 off++;
00728 w >>= 1;
00729 }
00730 }
00731 }
00732 output->blockno = page->blockno;
00733 output->ntuples = ntuples;
00734 output->recheck = page->recheck;
00735 iterator->spageptr++;
00736 return output;
00737 }
00738
00739
00740 return NULL;
00741 }
00742
00743
00744
00745
00746
00747
00748
00749
00750 void
00751 tbm_end_iterate(TBMIterator *iterator)
00752 {
00753 pfree(iterator);
00754 }
00755
00756
00757
00758
00759
00760
00761 static const PagetableEntry *
00762 tbm_find_pageentry(const TIDBitmap *tbm, BlockNumber pageno)
00763 {
00764 const PagetableEntry *page;
00765
00766 if (tbm->nentries == 0)
00767 return NULL;
00768
00769 if (tbm->status == TBM_ONE_PAGE)
00770 {
00771 page = &tbm->entry1;
00772 if (page->blockno != pageno)
00773 return NULL;
00774 Assert(!page->ischunk);
00775 return page;
00776 }
00777
00778 page = (PagetableEntry *) hash_search(tbm->pagetable,
00779 (void *) &pageno,
00780 HASH_FIND, NULL);
00781 if (page == NULL)
00782 return NULL;
00783 if (page->ischunk)
00784 return NULL;
00785 return page;
00786 }
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796 static PagetableEntry *
00797 tbm_get_pageentry(TIDBitmap *tbm, BlockNumber pageno)
00798 {
00799 PagetableEntry *page;
00800 bool found;
00801
00802 if (tbm->status == TBM_EMPTY)
00803 {
00804
00805 page = &tbm->entry1;
00806 found = false;
00807 tbm->status = TBM_ONE_PAGE;
00808 }
00809 else
00810 {
00811 if (tbm->status == TBM_ONE_PAGE)
00812 {
00813 page = &tbm->entry1;
00814 if (page->blockno == pageno)
00815 return page;
00816
00817 tbm_create_pagetable(tbm);
00818 }
00819
00820
00821 page = (PagetableEntry *) hash_search(tbm->pagetable,
00822 (void *) &pageno,
00823 HASH_ENTER, &found);
00824 }
00825
00826
00827 if (!found)
00828 {
00829 MemSet(page, 0, sizeof(PagetableEntry));
00830 page->blockno = pageno;
00831
00832 tbm->nentries++;
00833 tbm->npages++;
00834 }
00835
00836 return page;
00837 }
00838
00839
00840
00841
00842 static bool
00843 tbm_page_is_lossy(const TIDBitmap *tbm, BlockNumber pageno)
00844 {
00845 PagetableEntry *page;
00846 BlockNumber chunk_pageno;
00847 int bitno;
00848
00849
00850 if (tbm->nchunks == 0)
00851 return false;
00852 Assert(tbm->status == TBM_HASH);
00853
00854 bitno = pageno % PAGES_PER_CHUNK;
00855 chunk_pageno = pageno - bitno;
00856 page = (PagetableEntry *) hash_search(tbm->pagetable,
00857 (void *) &chunk_pageno,
00858 HASH_FIND, NULL);
00859 if (page != NULL && page->ischunk)
00860 {
00861 int wordnum = WORDNUM(bitno);
00862 int bitnum = BITNUM(bitno);
00863
00864 if ((page->words[wordnum] & ((bitmapword) 1 << bitnum)) != 0)
00865 return true;
00866 }
00867 return false;
00868 }
00869
00870
00871
00872
00873
00874
00875
00876 static void
00877 tbm_mark_page_lossy(TIDBitmap *tbm, BlockNumber pageno)
00878 {
00879 PagetableEntry *page;
00880 bool found;
00881 BlockNumber chunk_pageno;
00882 int bitno;
00883 int wordnum;
00884 int bitnum;
00885
00886
00887 if (tbm->status != TBM_HASH)
00888 tbm_create_pagetable(tbm);
00889
00890 bitno = pageno % PAGES_PER_CHUNK;
00891 chunk_pageno = pageno - bitno;
00892
00893
00894
00895
00896
00897 if (bitno != 0)
00898 {
00899 if (hash_search(tbm->pagetable,
00900 (void *) &pageno,
00901 HASH_REMOVE, NULL) != NULL)
00902 {
00903
00904 tbm->nentries--;
00905 tbm->npages--;
00906 }
00907 }
00908
00909
00910 page = (PagetableEntry *) hash_search(tbm->pagetable,
00911 (void *) &chunk_pageno,
00912 HASH_ENTER, &found);
00913
00914
00915 if (!found)
00916 {
00917 MemSet(page, 0, sizeof(PagetableEntry));
00918 page->blockno = chunk_pageno;
00919 page->ischunk = true;
00920
00921 tbm->nentries++;
00922 tbm->nchunks++;
00923 }
00924 else if (!page->ischunk)
00925 {
00926
00927 MemSet(page, 0, sizeof(PagetableEntry));
00928 page->blockno = chunk_pageno;
00929 page->ischunk = true;
00930
00931 page->words[0] = ((bitmapword) 1 << 0);
00932
00933 tbm->nchunks++;
00934 tbm->npages--;
00935 }
00936
00937
00938 wordnum = WORDNUM(bitno);
00939 bitnum = BITNUM(bitno);
00940 page->words[wordnum] |= ((bitmapword) 1 << bitnum);
00941 }
00942
00943
00944
00945
00946 static void
00947 tbm_lossify(TIDBitmap *tbm)
00948 {
00949 HASH_SEQ_STATUS status;
00950 PagetableEntry *page;
00951
00952
00953
00954
00955
00956
00957
00958
00959
00960
00961 Assert(!tbm->iterating);
00962 Assert(tbm->status == TBM_HASH);
00963
00964 hash_seq_init(&status, tbm->pagetable);
00965 while ((page = (PagetableEntry *) hash_seq_search(&status)) != NULL)
00966 {
00967 if (page->ischunk)
00968 continue;
00969
00970
00971
00972
00973
00974 if ((page->blockno % PAGES_PER_CHUNK) == 0)
00975 continue;
00976
00977
00978 tbm_mark_page_lossy(tbm, page->blockno);
00979
00980 if (tbm->nentries <= tbm->maxentries / 2)
00981 {
00982
00983 hash_seq_term(&status);
00984 break;
00985 }
00986
00987
00988
00989
00990
00991
00992 }
00993
00994
00995
00996
00997
00998
00999
01000
01001
01002
01003
01004 if (tbm->nentries > tbm->maxentries / 2)
01005 tbm->maxentries = Min(tbm->nentries, (INT_MAX - 1) / 2) * 2;
01006 }
01007
01008
01009
01010
01011 static int
01012 tbm_comparator(const void *left, const void *right)
01013 {
01014 BlockNumber l = (*((PagetableEntry *const *) left))->blockno;
01015 BlockNumber r = (*((PagetableEntry *const *) right))->blockno;
01016
01017 if (l < r)
01018 return -1;
01019 else if (l > r)
01020 return 1;
01021 return 0;
01022 }