mirror of
https://github.com/postgres/postgres.git
synced 2025-11-16 15:02:33 +03:00
Arrange to cache btree metapage data in the relcache entry for the index,
thereby saving a visit to the metapage in most index searches/updates. This wouldn't actually save any I/O (since in the old regime the metapage generally stayed in cache anyway), but it does provide a useful decrease in bufmgr traffic in high-contention scenarios. Per my recent proposal.
This commit is contained in:
@@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtpage.c,v 1.95 2006/04/01 03:03:36 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtpage.c,v 1.96 2006/04/25 22:46:05 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* Postgres btree pages look like ordinary relation pages. The opaque
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "miscadmin.h"
|
||||
#include "storage/freespace.h"
|
||||
#include "storage/lmgr.h"
|
||||
#include "utils/inval.h"
|
||||
|
||||
|
||||
/*
|
||||
@@ -99,6 +100,49 @@ _bt_getroot(Relation rel, int access)
|
||||
uint32 rootlevel;
|
||||
BTMetaPageData *metad;
|
||||
|
||||
/*
|
||||
* Try to use previously-cached metapage data to find the root. This
|
||||
* normally saves one buffer access per index search, which is a very
|
||||
* helpful savings in bufmgr traffic and hence contention.
|
||||
*/
|
||||
if (rel->rd_amcache != NULL)
|
||||
{
|
||||
metad = (BTMetaPageData *) rel->rd_amcache;
|
||||
/* We shouldn't have cached it if any of these fail */
|
||||
Assert(metad->btm_magic == BTREE_MAGIC);
|
||||
Assert(metad->btm_version == BTREE_VERSION);
|
||||
Assert(metad->btm_root != P_NONE);
|
||||
|
||||
rootblkno = metad->btm_fastroot;
|
||||
Assert(rootblkno != P_NONE);
|
||||
rootlevel = metad->btm_fastlevel;
|
||||
|
||||
rootbuf = _bt_getbuf(rel, rootblkno, BT_READ);
|
||||
rootpage = BufferGetPage(rootbuf);
|
||||
rootopaque = (BTPageOpaque) PageGetSpecialPointer(rootpage);
|
||||
|
||||
/*
|
||||
* Since the cache might be stale, we check the page more carefully
|
||||
* here than normal. We *must* check that it's not deleted.
|
||||
* If it's not alone on its level, then we reject too --- this
|
||||
* may be overly paranoid but better safe than sorry. Note we
|
||||
* don't check P_ISROOT, because that's not set in a "fast root".
|
||||
*/
|
||||
if (!P_IGNORE(rootopaque) &&
|
||||
rootopaque->btpo.level == rootlevel &&
|
||||
P_LEFTMOST(rootopaque) &&
|
||||
P_RIGHTMOST(rootopaque))
|
||||
{
|
||||
/* OK, accept cached page as the root */
|
||||
return rootbuf;
|
||||
}
|
||||
_bt_relbuf(rel, rootbuf);
|
||||
/* Cache is stale, throw it away */
|
||||
if (rel->rd_amcache)
|
||||
pfree(rel->rd_amcache);
|
||||
rel->rd_amcache = NULL;
|
||||
}
|
||||
|
||||
metabuf = _bt_getbuf(rel, BTREE_METAPAGE, BT_READ);
|
||||
metapg = BufferGetPage(metabuf);
|
||||
metaopaque = (BTPageOpaque) PageGetSpecialPointer(metapg);
|
||||
@@ -200,6 +244,12 @@ _bt_getroot(Relation rel, int access)
|
||||
|
||||
END_CRIT_SECTION();
|
||||
|
||||
/*
|
||||
* Send out relcache inval for metapage change (probably unnecessary
|
||||
* here, but let's be safe).
|
||||
*/
|
||||
CacheInvalidateRelcache(rel);
|
||||
|
||||
/*
|
||||
* swap root write lock for read lock. There is no danger of anyone
|
||||
* else accessing the new root page while it's unlocked, since no one
|
||||
@@ -217,6 +267,13 @@ _bt_getroot(Relation rel, int access)
|
||||
Assert(rootblkno != P_NONE);
|
||||
rootlevel = metad->btm_fastlevel;
|
||||
|
||||
/*
|
||||
* Cache the metapage data for next time
|
||||
*/
|
||||
rel->rd_amcache = MemoryContextAlloc(rel->rd_indexcxt,
|
||||
sizeof(BTMetaPageData));
|
||||
memcpy(rel->rd_amcache, metad, sizeof(BTMetaPageData));
|
||||
|
||||
/*
|
||||
* We are done with the metapage; arrange to release it via first
|
||||
* _bt_relandgetbuf call
|
||||
@@ -280,6 +337,16 @@ _bt_gettrueroot(Relation rel)
|
||||
uint32 rootlevel;
|
||||
BTMetaPageData *metad;
|
||||
|
||||
/*
|
||||
* We don't try to use cached metapage data here, since (a) this path is
|
||||
* not performance-critical, and (b) if we are here it suggests our cache
|
||||
* is out-of-date anyway. In light of point (b), it's probably safest to
|
||||
* actively flush any cached metapage info.
|
||||
*/
|
||||
if (rel->rd_amcache)
|
||||
pfree(rel->rd_amcache);
|
||||
rel->rd_amcache = NULL;
|
||||
|
||||
metabuf = _bt_getbuf(rel, BTREE_METAPAGE, BT_READ);
|
||||
metapg = BufferGetPage(metabuf);
|
||||
metaopaque = (BTPageOpaque) PageGetSpecialPointer(metapg);
|
||||
@@ -1052,9 +1119,12 @@ _bt_pagedel(Relation rel, Buffer buf, bool vacuum_full)
|
||||
|
||||
END_CRIT_SECTION();
|
||||
|
||||
/* release buffers */
|
||||
/* release buffers; send out relcache inval if metapage changed */
|
||||
if (BufferIsValid(metabuf))
|
||||
{
|
||||
CacheInvalidateRelcache(rel);
|
||||
_bt_relbuf(rel, metabuf);
|
||||
}
|
||||
_bt_relbuf(rel, pbuf);
|
||||
_bt_relbuf(rel, rbuf);
|
||||
_bt_relbuf(rel, buf);
|
||||
|
||||
Reference in New Issue
Block a user