📄 hashovfl.c
字号:
_hash_checkpage((Page) metap, LH_META_PAGE); ovflpage = BufferGetPage(ovflbuf); _hash_checkpage(ovflpage, LH_OVERFLOW_PAGE); ovflopaque = (HashPageOpaque) PageGetSpecialPointer(ovflpage); addr = ovflopaque->hasho_oaddr; nextblkno = ovflopaque->hasho_nextblkno; prevblkno = ovflopaque->hasho_prevblkno; bucket = ovflopaque->hasho_bucket; MemSet(ovflpage, 0, BufferGetPageSize(ovflbuf)); _hash_wrtbuf(rel, ovflbuf); /* * fix up the bucket chain. this is a doubly-linked list, so we must * fix up the bucket chain members behind and ahead of the overflow * page being deleted. * * XXX this should look like: - lock prev/next - modify/write prev/next * (how to do write ordering with a doubly-linked list?) - unlock * prev/next */ if (BlockNumberIsValid(prevblkno)) { Buffer prevbuf = _hash_getbuf(rel, prevblkno, HASH_WRITE); Page prevpage = BufferGetPage(prevbuf); HashPageOpaque prevopaque = (HashPageOpaque) PageGetSpecialPointer(prevpage); _hash_checkpage(prevpage, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE); Assert(prevopaque->hasho_bucket == bucket); prevopaque->hasho_nextblkno = nextblkno; _hash_wrtbuf(rel, prevbuf); } if (BlockNumberIsValid(nextblkno)) { Buffer nextbuf = _hash_getbuf(rel, nextblkno, HASH_WRITE); Page nextpage = BufferGetPage(nextbuf); HashPageOpaque nextopaque = (HashPageOpaque) PageGetSpecialPointer(nextpage); _hash_checkpage(nextpage, LH_OVERFLOW_PAGE); Assert(nextopaque->hasho_bucket == bucket); nextopaque->hasho_prevblkno = prevblkno; _hash_wrtbuf(rel, nextbuf); } /* * Fix up the overflow page bitmap that tracks this particular * overflow page. The bitmap can be found in the MetaPageData array * element hashm_mapp[bitmappage]. */ splitnum = (addr >> SPLITSHIFT); ovflpgno = (splitnum ? metap->SPARES[splitnum - 1] : 0) + (addr & SPLITMASK) - 1; if (ovflpgno < metap->LAST_FREED) metap->LAST_FREED = ovflpgno; bitmappage = (ovflpgno >> (metap->hashm_bshift + BYTE_TO_BIT)); bitmapbit = ovflpgno & (BMPGSZ_BIT(metap) - 1); blkno = metap->hashm_mapp[bitmappage]; mapbuf = _hash_getbuf(rel, blkno, HASH_WRITE); mappage = BufferGetPage(mapbuf); _hash_checkpage(mappage, LH_BITMAP_PAGE); freep = HashPageGetBitmap(mappage); CLRBIT(freep, bitmapbit); _hash_wrtbuf(rel, mapbuf); _hash_relbuf(rel, metabuf, HASH_WRITE); /* * now instantiate the page that replaced this one, if it exists, and * return that buffer with a write lock. */ if (BlockNumberIsValid(nextblkno)) return _hash_getbuf(rel, nextblkno, HASH_WRITE); else return InvalidBuffer;}/* * _hash_initbitmap() * * Initialize a new bitmap page. The metapage has a write-lock upon * entering the function. * * 'pnum' is the OverflowPageAddress of the new bitmap page. * 'nbits' is how many bits to clear (i.e., make available) in the new * bitmap page. the remainder of the bits (as well as the first bit, * representing the bitmap page itself) will be set. * 'ndx' is the 0-based offset of the new bitmap page within the * metapage's array of bitmap page OverflowPageAddresses. */#define INT_MASK ((1 << INT_TO_BIT) -1)int32_hash_initbitmap(Relation rel, HashMetaPage metap, int32 pnum, int32 nbits, int32 ndx){ Buffer buf; BlockNumber blkno; Page pg; HashPageOpaque op; uint32 *freep; int clearbytes, clearints; blkno = OADDR_TO_BLKNO(pnum); buf = _hash_getbuf(rel, blkno, HASH_WRITE); pg = BufferGetPage(buf); _hash_pageinit(pg, BufferGetPageSize(buf)); op = (HashPageOpaque) PageGetSpecialPointer(pg); op->hasho_oaddr = InvalidOvflAddress; op->hasho_prevblkno = InvalidBlockNumber; op->hasho_nextblkno = InvalidBlockNumber; op->hasho_flag = LH_BITMAP_PAGE; op->hasho_bucket = -1; freep = HashPageGetBitmap(pg); /* set all of the bits above 'nbits' to 1 */ clearints = ((nbits - 1) >> INT_TO_BIT) + 1; clearbytes = clearints << INT_TO_BYTE; MemSet((char *) freep, 0, clearbytes); MemSet(((char *) freep) + clearbytes, 0xFF, BMPGSZ_BYTE(metap) - clearbytes); freep[clearints - 1] = ALL_SET << (nbits & INT_MASK); /* bit 0 represents the new bitmap page */ SETBIT(freep, 0); /* metapage already has a write lock */ metap->hashm_nmaps++; metap->hashm_mapp[ndx] = blkno; /* write out the new bitmap page (releasing its locks) */ _hash_wrtbuf(rel, buf); return 0;}/* * _hash_squeezebucket(rel, bucket) * * Try to squeeze the tuples onto pages occuring earlier in the * bucket chain in an attempt to free overflow pages. When we start * the "squeezing", the page from which we start taking tuples (the * "read" page) is the last bucket in the bucket chain and the page * onto which we start squeezing tuples (the "write" page) is the * first page in the bucket chain. The read page works backward and * the write page works forward; the procedure terminates when the * read page and write page are the same page. */void_hash_squeezebucket(Relation rel, HashMetaPage metap, Bucket bucket){ Buffer wbuf; Buffer rbuf = 0; BlockNumber wblkno; BlockNumber rblkno; Page wpage; Page rpage; HashPageOpaque wopaque; HashPageOpaque ropaque; OffsetNumber woffnum; OffsetNumber roffnum; HashItem hitem; int itemsz;/* elog(DEBUG, "_hash_squeezebucket: squeezing bucket %d", bucket); */ /* * start squeezing into the base bucket page. */ wblkno = BUCKET_TO_BLKNO(bucket); wbuf = _hash_getbuf(rel, wblkno, HASH_WRITE); wpage = BufferGetPage(wbuf); _hash_checkpage(wpage, LH_BUCKET_PAGE); wopaque = (HashPageOpaque) PageGetSpecialPointer(wpage); /* * if there aren't any overflow pages, there's nothing to squeeze. */ if (!BlockNumberIsValid(wopaque->hasho_nextblkno)) { _hash_relbuf(rel, wbuf, HASH_WRITE); return; } /* * find the last page in the bucket chain by starting at the base * bucket page and working forward. * * XXX if chains tend to be long, we should probably move forward using * HASH_READ and then _hash_chgbufaccess to HASH_WRITE when we reach * the end. if they are short we probably don't care very much. if * the hash function is working at all, they had better be short.. */ ropaque = wopaque; do { rblkno = ropaque->hasho_nextblkno; if (ropaque != wopaque) _hash_relbuf(rel, rbuf, HASH_WRITE); rbuf = _hash_getbuf(rel, rblkno, HASH_WRITE); rpage = BufferGetPage(rbuf); _hash_checkpage(rpage, LH_OVERFLOW_PAGE); Assert(!PageIsEmpty(rpage)); ropaque = (HashPageOpaque) PageGetSpecialPointer(rpage); Assert(ropaque->hasho_bucket == bucket); } while (BlockNumberIsValid(ropaque->hasho_nextblkno)); /* * squeeze the tuples. */ roffnum = FirstOffsetNumber; for (;;) { hitem = (HashItem) PageGetItem(rpage, PageGetItemId(rpage, roffnum)); itemsz = IndexTupleDSize(hitem->hash_itup) + (sizeof(HashItemData) - sizeof(IndexTupleData)); itemsz = MAXALIGN(itemsz); /* * walk up the bucket chain, looking for a page big enough for * this item. */ while (PageGetFreeSpace(wpage) < itemsz) { wblkno = wopaque->hasho_nextblkno; _hash_wrtbuf(rel, wbuf); if (!BlockNumberIsValid(wblkno) || (rblkno == wblkno)) { _hash_wrtbuf(rel, rbuf); /* wbuf is already released */ return; } wbuf = _hash_getbuf(rel, wblkno, HASH_WRITE); wpage = BufferGetPage(wbuf); _hash_checkpage(wpage, LH_OVERFLOW_PAGE); Assert(!PageIsEmpty(wpage)); wopaque = (HashPageOpaque) PageGetSpecialPointer(wpage); Assert(wopaque->hasho_bucket == bucket); } /* * if we're here, we have found room so insert on the "write" * page. */ woffnum = OffsetNumberNext(PageGetMaxOffsetNumber(wpage)); PageAddItem(wpage, (Item) hitem, itemsz, woffnum, LP_USED); /* * delete the tuple from the "read" page. PageIndexTupleDelete * repacks the ItemId array, so 'roffnum' will be "advanced" to * the "next" ItemId. */ PageIndexTupleDelete(rpage, roffnum); _hash_wrtnorelbuf(rel, rbuf); /* * if the "read" page is now empty because of the deletion, free * it. */ if (PageIsEmpty(rpage) && (ropaque->hasho_flag & LH_OVERFLOW_PAGE)) { rblkno = ropaque->hasho_prevblkno; Assert(BlockNumberIsValid(rblkno)); /* * free this overflow page. the extra _hash_relbuf is because * _hash_freeovflpage gratuitously returns the next page (we * want the previous page and will get it ourselves later). */ rbuf = _hash_freeovflpage(rel, rbuf); if (BufferIsValid(rbuf)) _hash_relbuf(rel, rbuf, HASH_WRITE); if (rblkno == wblkno) { /* rbuf is already released */ _hash_wrtbuf(rel, wbuf); return; } rbuf = _hash_getbuf(rel, rblkno, HASH_WRITE); rpage = BufferGetPage(rbuf); _hash_checkpage(rpage, LH_OVERFLOW_PAGE); Assert(!PageIsEmpty(rpage)); ropaque = (HashPageOpaque) PageGetSpecialPointer(rpage); Assert(ropaque->hasho_bucket == bucket); roffnum = FirstOffsetNumber; } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -