00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "postgres.h"
00025
00026 #include "access/htup_details.h"
00027 #include "access/xlogutils.h"
00028 #include "miscadmin.h"
00029 #include "storage/freespace.h"
00030 #include "storage/fsm_internals.h"
00031 #include "storage/lmgr.h"
00032 #include "storage/smgr.h"
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063 #define FSM_CATEGORIES 256
00064 #define FSM_CAT_STEP (BLCKSZ / FSM_CATEGORIES)
00065 #define MaxFSMRequestSize MaxHeapTupleSize
00066
00067
00068
00069
00070
00071
00072
00073
00074 #define FSM_TREE_DEPTH ((SlotsPerFSMPage >= 1626) ? 3 : 4)
00075
00076 #define FSM_ROOT_LEVEL (FSM_TREE_DEPTH - 1)
00077 #define FSM_BOTTOM_LEVEL 0
00078
00079
00080
00081
00082
00083 typedef struct
00084 {
00085 int level;
00086 int logpageno;
00087 } FSMAddress;
00088
00089
00090 static const FSMAddress FSM_ROOT_ADDRESS = {FSM_ROOT_LEVEL, 0};
00091
00092
00093 static FSMAddress fsm_get_child(FSMAddress parent, uint16 slot);
00094 static FSMAddress fsm_get_parent(FSMAddress child, uint16 *slot);
00095 static FSMAddress fsm_get_location(BlockNumber heapblk, uint16 *slot);
00096 static BlockNumber fsm_get_heap_blk(FSMAddress addr, uint16 slot);
00097 static BlockNumber fsm_logical_to_physical(FSMAddress addr);
00098
00099 static Buffer fsm_readbuf(Relation rel, FSMAddress addr, bool extend);
00100 static void fsm_extend(Relation rel, BlockNumber fsm_nblocks);
00101
00102
00103 static uint8 fsm_space_avail_to_cat(Size avail);
00104 static uint8 fsm_space_needed_to_cat(Size needed);
00105 static Size fsm_space_cat_to_avail(uint8 cat);
00106
00107
00108 static int fsm_set_and_search(Relation rel, FSMAddress addr, uint16 slot,
00109 uint8 newValue, uint8 minValue);
00110 static BlockNumber fsm_search(Relation rel, uint8 min_cat);
00111 static uint8 fsm_vacuum_page(Relation rel, FSMAddress addr, bool *eof);
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129 BlockNumber
00130 GetPageWithFreeSpace(Relation rel, Size spaceNeeded)
00131 {
00132 uint8 min_cat = fsm_space_needed_to_cat(spaceNeeded);
00133
00134 return fsm_search(rel, min_cat);
00135 }
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146 BlockNumber
00147 RecordAndGetPageWithFreeSpace(Relation rel, BlockNumber oldPage,
00148 Size oldSpaceAvail, Size spaceNeeded)
00149 {
00150 int old_cat = fsm_space_avail_to_cat(oldSpaceAvail);
00151 int search_cat = fsm_space_needed_to_cat(spaceNeeded);
00152 FSMAddress addr;
00153 uint16 slot;
00154 int search_slot;
00155
00156
00157 addr = fsm_get_location(oldPage, &slot);
00158
00159 search_slot = fsm_set_and_search(rel, addr, slot, old_cat, search_cat);
00160
00161
00162
00163
00164
00165 if (search_slot != -1)
00166 return fsm_get_heap_blk(addr, search_slot);
00167 else
00168 return fsm_search(rel, search_cat);
00169 }
00170
00171
00172
00173
00174
00175
00176
00177
00178 void
00179 RecordPageWithFreeSpace(Relation rel, BlockNumber heapBlk, Size spaceAvail)
00180 {
00181 int new_cat = fsm_space_avail_to_cat(spaceAvail);
00182 FSMAddress addr;
00183 uint16 slot;
00184
00185
00186 addr = fsm_get_location(heapBlk, &slot);
00187
00188 fsm_set_and_search(rel, addr, slot, new_cat, 0);
00189 }
00190
00191
00192
00193
00194
00195 void
00196 XLogRecordPageWithFreeSpace(RelFileNode rnode, BlockNumber heapBlk,
00197 Size spaceAvail)
00198 {
00199 int new_cat = fsm_space_avail_to_cat(spaceAvail);
00200 FSMAddress addr;
00201 uint16 slot;
00202 BlockNumber blkno;
00203 Buffer buf;
00204 Page page;
00205
00206
00207 addr = fsm_get_location(heapBlk, &slot);
00208 blkno = fsm_logical_to_physical(addr);
00209
00210
00211 buf = XLogReadBufferExtended(rnode, FSM_FORKNUM, blkno, RBM_ZERO_ON_ERROR);
00212 LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
00213
00214 page = BufferGetPage(buf);
00215 if (PageIsNew(page))
00216 PageInit(page, BLCKSZ, 0);
00217
00218 if (fsm_set_avail(page, slot, new_cat))
00219 MarkBufferDirtyHint(buf);
00220 UnlockReleaseBuffer(buf);
00221 }
00222
00223
00224
00225
00226
00227 Size
00228 GetRecordedFreeSpace(Relation rel, BlockNumber heapBlk)
00229 {
00230 FSMAddress addr;
00231 uint16 slot;
00232 Buffer buf;
00233 uint8 cat;
00234
00235
00236 addr = fsm_get_location(heapBlk, &slot);
00237
00238 buf = fsm_readbuf(rel, addr, false);
00239 if (!BufferIsValid(buf))
00240 return 0;
00241 cat = fsm_get_avail(BufferGetPage(buf), slot);
00242 ReleaseBuffer(buf);
00243
00244 return fsm_space_cat_to_avail(cat);
00245 }
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256 void
00257 FreeSpaceMapTruncateRel(Relation rel, BlockNumber nblocks)
00258 {
00259 BlockNumber new_nfsmblocks;
00260 FSMAddress first_removed_address;
00261 uint16 first_removed_slot;
00262 Buffer buf;
00263
00264 RelationOpenSmgr(rel);
00265
00266
00267
00268
00269
00270 if (!smgrexists(rel->rd_smgr, FSM_FORKNUM))
00271 return;
00272
00273
00274 first_removed_address = fsm_get_location(nblocks, &first_removed_slot);
00275
00276
00277
00278
00279
00280
00281
00282 if (first_removed_slot > 0)
00283 {
00284 buf = fsm_readbuf(rel, first_removed_address, false);
00285 if (!BufferIsValid(buf))
00286 return;
00287 LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
00288 fsm_truncate_avail(BufferGetPage(buf), first_removed_slot);
00289 MarkBufferDirtyHint(buf);
00290 UnlockReleaseBuffer(buf);
00291
00292 new_nfsmblocks = fsm_logical_to_physical(first_removed_address) + 1;
00293 }
00294 else
00295 {
00296 new_nfsmblocks = fsm_logical_to_physical(first_removed_address);
00297 if (smgrnblocks(rel->rd_smgr, FSM_FORKNUM) <= new_nfsmblocks)
00298 return;
00299 }
00300
00301
00302 smgrtruncate(rel->rd_smgr, FSM_FORKNUM, new_nfsmblocks);
00303
00304
00305
00306
00307
00308
00309
00310
00311 if (rel->rd_smgr)
00312 rel->rd_smgr->smgr_fsm_nblocks = new_nfsmblocks;
00313 }
00314
00315
00316
00317
00318 void
00319 FreeSpaceMapVacuum(Relation rel)
00320 {
00321 bool dummy;
00322
00323
00324
00325
00326
00327 fsm_vacuum_page(rel, FSM_ROOT_ADDRESS, &dummy);
00328 }
00329
00330
00331
00332
00333
00334
00335 static uint8
00336 fsm_space_avail_to_cat(Size avail)
00337 {
00338 int cat;
00339
00340 Assert(avail < BLCKSZ);
00341
00342 if (avail >= MaxFSMRequestSize)
00343 return 255;
00344
00345 cat = avail / FSM_CAT_STEP;
00346
00347
00348
00349
00350
00351 if (cat > 254)
00352 cat = 254;
00353
00354 return (uint8) cat;
00355 }
00356
00357
00358
00359
00360
00361 static Size
00362 fsm_space_cat_to_avail(uint8 cat)
00363 {
00364
00365 if (cat == 255)
00366 return MaxFSMRequestSize;
00367 else
00368 return cat * FSM_CAT_STEP;
00369 }
00370
00371
00372
00373
00374
00375 static uint8
00376 fsm_space_needed_to_cat(Size needed)
00377 {
00378 int cat;
00379
00380
00381 if (needed > MaxFSMRequestSize)
00382 elog(ERROR, "invalid FSM request size %lu",
00383 (unsigned long) needed);
00384
00385 if (needed == 0)
00386 return 1;
00387
00388 cat = (needed + FSM_CAT_STEP - 1) / FSM_CAT_STEP;
00389
00390 if (cat > 255)
00391 cat = 255;
00392
00393 return (uint8) cat;
00394 }
00395
00396
00397
00398
00399 static BlockNumber
00400 fsm_logical_to_physical(FSMAddress addr)
00401 {
00402 BlockNumber pages;
00403 int leafno;
00404 int l;
00405
00406
00407
00408
00409
00410 leafno = addr.logpageno;
00411 for (l = 0; l < addr.level; l++)
00412 leafno *= SlotsPerFSMPage;
00413
00414
00415 pages = 0;
00416 for (l = 0; l < FSM_TREE_DEPTH; l++)
00417 {
00418 pages += leafno + 1;
00419 leafno /= SlotsPerFSMPage;
00420 }
00421
00422
00423
00424
00425
00426 pages -= addr.level;
00427
00428
00429 return pages - 1;
00430 }
00431
00432
00433
00434
00435 static FSMAddress
00436 fsm_get_location(BlockNumber heapblk, uint16 *slot)
00437 {
00438 FSMAddress addr;
00439
00440 addr.level = FSM_BOTTOM_LEVEL;
00441 addr.logpageno = heapblk / SlotsPerFSMPage;
00442 *slot = heapblk % SlotsPerFSMPage;
00443
00444 return addr;
00445 }
00446
00447
00448
00449
00450 static BlockNumber
00451 fsm_get_heap_blk(FSMAddress addr, uint16 slot)
00452 {
00453 Assert(addr.level == FSM_BOTTOM_LEVEL);
00454 return ((unsigned int) addr.logpageno) * SlotsPerFSMPage + slot;
00455 }
00456
00457
00458
00459
00460
00461 static FSMAddress
00462 fsm_get_parent(FSMAddress child, uint16 *slot)
00463 {
00464 FSMAddress parent;
00465
00466 Assert(child.level < FSM_ROOT_LEVEL);
00467
00468 parent.level = child.level + 1;
00469 parent.logpageno = child.logpageno / SlotsPerFSMPage;
00470 *slot = child.logpageno % SlotsPerFSMPage;
00471
00472 return parent;
00473 }
00474
00475
00476
00477
00478
00479 static FSMAddress
00480 fsm_get_child(FSMAddress parent, uint16 slot)
00481 {
00482 FSMAddress child;
00483
00484 Assert(parent.level > FSM_BOTTOM_LEVEL);
00485
00486 child.level = parent.level - 1;
00487 child.logpageno = parent.logpageno * SlotsPerFSMPage + slot;
00488
00489 return child;
00490 }
00491
00492
00493
00494
00495
00496
00497
00498 static Buffer
00499 fsm_readbuf(Relation rel, FSMAddress addr, bool extend)
00500 {
00501 BlockNumber blkno = fsm_logical_to_physical(addr);
00502 Buffer buf;
00503
00504 RelationOpenSmgr(rel);
00505
00506
00507
00508
00509
00510
00511
00512 if (rel->rd_smgr->smgr_fsm_nblocks == InvalidBlockNumber ||
00513 blkno >= rel->rd_smgr->smgr_fsm_nblocks)
00514 {
00515 if (smgrexists(rel->rd_smgr, FSM_FORKNUM))
00516 rel->rd_smgr->smgr_fsm_nblocks = smgrnblocks(rel->rd_smgr,
00517 FSM_FORKNUM);
00518 else
00519 rel->rd_smgr->smgr_fsm_nblocks = 0;
00520 }
00521
00522
00523 if (blkno >= rel->rd_smgr->smgr_fsm_nblocks)
00524 {
00525 if (extend)
00526 fsm_extend(rel, blkno + 1);
00527 else
00528 return InvalidBuffer;
00529 }
00530
00531
00532
00533
00534
00535
00536
00537
00538 buf = ReadBufferExtended(rel, FSM_FORKNUM, blkno, RBM_ZERO_ON_ERROR, NULL);
00539 if (PageIsNew(BufferGetPage(buf)))
00540 PageInit(BufferGetPage(buf), BLCKSZ, 0);
00541 return buf;
00542 }
00543
00544
00545
00546
00547
00548
00549 static void
00550 fsm_extend(Relation rel, BlockNumber fsm_nblocks)
00551 {
00552 BlockNumber fsm_nblocks_now;
00553 Page pg;
00554
00555 pg = (Page) palloc(BLCKSZ);
00556 PageInit(pg, BLCKSZ, 0);
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568 LockRelationForExtension(rel, ExclusiveLock);
00569
00570
00571 RelationOpenSmgr(rel);
00572
00573
00574
00575
00576
00577 if ((rel->rd_smgr->smgr_fsm_nblocks == 0 ||
00578 rel->rd_smgr->smgr_fsm_nblocks == InvalidBlockNumber) &&
00579 !smgrexists(rel->rd_smgr, FSM_FORKNUM))
00580 smgrcreate(rel->rd_smgr, FSM_FORKNUM, false);
00581
00582 fsm_nblocks_now = smgrnblocks(rel->rd_smgr, FSM_FORKNUM);
00583
00584 while (fsm_nblocks_now < fsm_nblocks)
00585 {
00586 PageSetChecksumInplace(pg, fsm_nblocks_now);
00587
00588 smgrextend(rel->rd_smgr, FSM_FORKNUM, fsm_nblocks_now,
00589 (char *) pg, false);
00590 fsm_nblocks_now++;
00591 }
00592
00593
00594 rel->rd_smgr->smgr_fsm_nblocks = fsm_nblocks_now;
00595
00596 UnlockRelationForExtension(rel, ExclusiveLock);
00597
00598 pfree(pg);
00599 }
00600
00601
00602
00603
00604
00605
00606
00607
00608 static int
00609 fsm_set_and_search(Relation rel, FSMAddress addr, uint16 slot,
00610 uint8 newValue, uint8 minValue)
00611 {
00612 Buffer buf;
00613 Page page;
00614 int newslot = -1;
00615
00616 buf = fsm_readbuf(rel, addr, true);
00617 LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
00618
00619 page = BufferGetPage(buf);
00620
00621 if (fsm_set_avail(page, slot, newValue))
00622 MarkBufferDirtyHint(buf);
00623
00624 if (minValue != 0)
00625 {
00626
00627 newslot = fsm_search_avail(buf, minValue,
00628 addr.level == FSM_BOTTOM_LEVEL,
00629 true);
00630 }
00631
00632 UnlockReleaseBuffer(buf);
00633
00634 return newslot;
00635 }
00636
00637
00638
00639
00640 static BlockNumber
00641 fsm_search(Relation rel, uint8 min_cat)
00642 {
00643 int restarts = 0;
00644 FSMAddress addr = FSM_ROOT_ADDRESS;
00645
00646 for (;;)
00647 {
00648 int slot;
00649 Buffer buf;
00650 uint8 max_avail = 0;
00651
00652
00653 buf = fsm_readbuf(rel, addr, false);
00654
00655
00656 if (BufferIsValid(buf))
00657 {
00658 LockBuffer(buf, BUFFER_LOCK_SHARE);
00659 slot = fsm_search_avail(buf, min_cat,
00660 (addr.level == FSM_BOTTOM_LEVEL),
00661 false);
00662 if (slot == -1)
00663 max_avail = fsm_get_max_avail(BufferGetPage(buf));
00664 UnlockReleaseBuffer(buf);
00665 }
00666 else
00667 slot = -1;
00668
00669 if (slot != -1)
00670 {
00671
00672
00673
00674
00675 if (addr.level == FSM_BOTTOM_LEVEL)
00676 return fsm_get_heap_blk(addr, slot);
00677
00678 addr = fsm_get_child(addr, slot);
00679 }
00680 else if (addr.level == FSM_ROOT_LEVEL)
00681 {
00682
00683
00684
00685
00686 return InvalidBlockNumber;
00687 }
00688 else
00689 {
00690 uint16 parentslot;
00691 FSMAddress parent;
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705 parent = fsm_get_parent(addr, &parentslot);
00706 fsm_set_and_search(rel, parent, parentslot, max_avail, 0);
00707
00708
00709
00710
00711
00712
00713
00714
00715 if (restarts++ > 10000)
00716 return InvalidBlockNumber;
00717
00718
00719 addr = FSM_ROOT_ADDRESS;
00720 }
00721 }
00722 }
00723
00724
00725
00726
00727
00728 static uint8
00729 fsm_vacuum_page(Relation rel, FSMAddress addr, bool *eof_p)
00730 {
00731 Buffer buf;
00732 Page page;
00733 uint8 max_avail;
00734
00735
00736 buf = fsm_readbuf(rel, addr, false);
00737 if (!BufferIsValid(buf))
00738 {
00739 *eof_p = true;
00740 return 0;
00741 }
00742 else
00743 *eof_p = false;
00744
00745 page = BufferGetPage(buf);
00746
00747
00748
00749
00750
00751 if (addr.level > FSM_BOTTOM_LEVEL)
00752 {
00753 int slot;
00754 bool eof = false;
00755
00756 for (slot = 0; slot < SlotsPerFSMPage; slot++)
00757 {
00758 int child_avail;
00759
00760 CHECK_FOR_INTERRUPTS();
00761
00762
00763 if (!eof)
00764 child_avail = fsm_vacuum_page(rel, fsm_get_child(addr, slot), &eof);
00765 else
00766 child_avail = 0;
00767
00768
00769 if (fsm_get_avail(page, slot) != child_avail)
00770 {
00771 LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
00772 fsm_set_avail(BufferGetPage(buf), slot, child_avail);
00773 MarkBufferDirtyHint(buf);
00774 LockBuffer(buf, BUFFER_LOCK_UNLOCK);
00775 }
00776 }
00777 }
00778
00779 max_avail = fsm_get_max_avail(BufferGetPage(buf));
00780
00781
00782
00783
00784
00785
00786 ((FSMPage) PageGetContents(page))->fp_next_slot = 0;
00787
00788 ReleaseBuffer(buf);
00789
00790 return max_avail;
00791 }