/* * Update lastUsedPages cache when done modifying a page. * * We update the appropriate cache entry if it already contained this page * (its freeSpace is likely obsolete), or if this page has more space than * whatever we had cached. */ void SpGistSetLastUsedPage(Relation index, Buffer buffer) { SpGistCache *cache = spgGetCache(index); SpGistLastUsedPage *lup; int freeSpace; Page page = BufferGetPage(buffer); BlockNumber blkno = BufferGetBlockNumber(buffer); int flags; /* Never enter fixed pages (root pages) in cache, though */ if (SpGistBlockIsFixed(blkno)) return; if (SpGistPageIsLeaf(page)) flags = GBUF_LEAF; else flags = GBUF_INNER_PARITY(blkno); if (SpGistPageStoresNulls(page)) flags |= GBUF_NULLS; lup = GET_LUP(cache, flags); freeSpace = PageGetExactFreeSpace(page); if (lup->blkno == InvalidBlockNumber || lup->blkno == blkno || lup->freeSpace < freeSpace) { lup->blkno = blkno; lup->freeSpace = freeSpace; } }
/* * Update lastUsedPages cache when done modifying a page. * * We update the appropriate cache entry if it already contained this page * (its freeSpace is likely obsolete), or if this page has more space than * whatever we had cached. */ void SpGistSetLastUsedPage(Relation index, Buffer buffer) { SpGistCache *cache = spgGetCache(index); SpGistLastUsedPage *lup; int freeSpace; Page page = BufferGetPage(buffer); BlockNumber blkno = BufferGetBlockNumber(buffer); int flags; /* Never enter the root page in cache, though */ if (blkno == SPGIST_HEAD_BLKNO) return; if (SpGistPageIsLeaf(page)) flags = GBUF_LEAF; else flags = GBUF_INNER_PARITY(blkno); lup = GET_LUP(cache, flags); freeSpace = PageGetExactFreeSpace(page); if (lup->blkno == InvalidBlockNumber || lup->blkno == blkno || lup->freeSpace < freeSpace) { lup->blkno = blkno; lup->freeSpace = freeSpace; } }
/* * Allocate and initialize a new buffer of the type and parity specified by * flags. The returned buffer is already pinned and exclusive-locked. * * When requesting an inner page, if we get one with the wrong parity, * we just release the buffer and try again. We will get a different page * because GetFreeIndexPage will have marked the page used in FSM. The page * is entered in our local lastUsedPages cache, so there's some hope of * making use of it later in this session, but otherwise we rely on VACUUM * to eventually re-enter the page in FSM, making it available for recycling. * Note that such a page does not get marked dirty here, so unless it's used * fairly soon, the buffer will just get discarded and the page will remain * as it was on disk. * * When we return a buffer to the caller, the page is *not* entered into * the lastUsedPages cache; we expect the caller will do so after it's taken * whatever space it will use. This is because after the caller has used up * some space, the page might have less space than whatever was cached already * so we'd rather not trash the old cache entry. */ static Buffer allocNewBuffer(Relation index, int flags) { SpGistCache *cache = spgGetCache(index); uint16 pageflags = 0; if (GBUF_REQ_LEAF(flags)) pageflags |= SPGIST_LEAF; if (GBUF_REQ_NULLS(flags)) pageflags |= SPGIST_NULLS; for (;;) { Buffer buffer; buffer = SpGistNewBuffer(index); SpGistInitBuffer(buffer, pageflags); if (pageflags & SPGIST_LEAF) { /* Leaf pages have no parity concerns, so just use it */ return buffer; } else { BlockNumber blkno = BufferGetBlockNumber(buffer); int blkFlags = GBUF_INNER_PARITY(blkno); if ((flags & GBUF_PARITY_MASK) == blkFlags) { /* Page has right parity, use it */ return buffer; } else { /* Page has wrong parity, record it in cache and try again */ if (pageflags & SPGIST_NULLS) blkFlags |= GBUF_NULLS; cache->lastUsedPages.cachedPage[blkFlags].blkno = blkno; cache->lastUsedPages.cachedPage[blkFlags].freeSpace = PageGetExactFreeSpace(BufferGetPage(buffer)); UnlockReleaseBuffer(buffer); } } } }