From: Robert Haas Date: Wed, 13 Jun 2012 02:19:28 +0000 (-0400) Subject: Try to make the world safe for heap metapages. X-Git-Url: http://git.postgresql.org/gitweb/static/developers.postgresql.org?a=commitdiff_plain;h=e51538e075e729e41090b24669e2a543dcbae1ae;p=users%2Frhaas%2Fpostgres.git Try to make the world safe for heap metapages. --- diff --git a/src/backend/access/common/metapage.c b/src/backend/access/common/metapage.c index 3606a133ab..b143c55e77 100644 --- a/src/backend/access/common/metapage.c +++ b/src/backend/access/common/metapage.c @@ -71,31 +71,44 @@ RelationGetMetadata(Relation relation) meta = (RelationMetapage) MemoryContextAllocZero(CacheMemoryContext, sizeof(RelationMetapageData)); - /* Read and metapage. */ - buffer = ReadBuffer(relation, METAPAGE_BLKNO); - page = BufferGetPage(buffer); - LockBuffer(buffer, BUFFER_LOCK_SHARE); - - /* Copy real metapage, or for backward compatibility, create a fake one. */ - if (PageIsRelationMetapage(page)) - { - memcpy(meta, BlindGetRelationMeta(page), sizeof(RelationMetapageData)); - UnlockReleaseBuffer(buffer); - } + /* + * If the relation has a metapage, read it. + * + * XXX: It's pretty annoying to have to call RelationGetNumberOfBlocks. + * Can't we have an RBM_ERROR option for ReadBufferExtended? + */ + if (RelationGetNumberOfBlocks(relation) > METAPAGE_BLKNO) { + buffer = ReadBuffer(relation, METAPAGE_BLKNO); + page = BufferGetPage(buffer); + LockBuffer(buffer, BUFFER_LOCK_SHARE); + + /* If it's a metapage, copy it, cache it, and return it. */ + if (PageIsRelationMetapage(page)) + { + memcpy(meta, BlindGetRelationMeta(page), + sizeof(RelationMetapageData)); + UnlockReleaseBuffer(buffer); + relation->rd_metapage = meta; + return meta; + } + + /* It wasn't actually a metapage, so let it go. */ UnlockReleaseBuffer(buffer); - meta->rmp_magic = METAPAGE_MAGIC; - meta->rmp_version = 0; /* fake metapage */ - meta->rmp_dboid = relation->rd_node.dbNode; - meta->rmp_tsoid = relation->rd_node.spcNode; - meta->rmp_reloid = RelationGetRelid(relation); - meta->rmp_relfilenode = relation->rd_node.relNode; - meta->rmp_flags = 0; - meta->rmp_minlayout = PG_PAGE_LAYOUT_VERSION; - meta->rmp_maxlayout = PG_PAGE_LAYOUT_VERSION; - meta->rmp_relfilenode_time = (pg_time_t) time(NULL); } + /* There's no real metapage, so create a fake one. */ + meta->rmp_magic = METAPAGE_MAGIC; + meta->rmp_version = 0; /* fake metapage */ + meta->rmp_dboid = relation->rd_node.dbNode; + meta->rmp_tsoid = relation->rd_node.spcNode; + meta->rmp_reloid = RelationGetRelid(relation); + meta->rmp_relfilenode = relation->rd_node.relNode; + meta->rmp_flags = 0; + meta->rmp_minlayout = PG_PAGE_LAYOUT_VERSION; + meta->rmp_maxlayout = PG_PAGE_LAYOUT_VERSION; + meta->rmp_relfilenode_time = 0; /* unknown creation time */ + /* Cache result for next time, and return it. */ relation->rd_metapage = meta; return meta; diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index f28026be0f..31807d8241 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -42,6 +42,7 @@ #include "access/heapam.h" #include "access/hio.h" +#include "access/metapage.h" #include "access/multixact.h" #include "access/relscan.h" #include "access/sysattr.h" @@ -162,11 +163,13 @@ initscan(HeapScanDesc scan, ScanKey key, bool is_rescan) { scan->rs_syncscan = true; scan->rs_startblock = ss_get_location(scan->rs_rd, scan->rs_nblocks); + if (scan->rs_startblock < scan->rs_lowpage) + scan->rs_startblock = scan->rs_lowpage; } else { scan->rs_syncscan = false; - scan->rs_startblock = 0; + scan->rs_startblock = scan->rs_lowpage; } scan->rs_inited = false; @@ -348,7 +351,7 @@ heapgettup(HeapScanDesc scan, /* * return null immediately if relation is empty */ - if (scan->rs_nblocks == 0) + if (scan->rs_nblocks == scan->rs_lowpage) { Assert(!BufferIsValid(scan->rs_cbuf)); tuple->t_data = NULL; @@ -382,7 +385,7 @@ heapgettup(HeapScanDesc scan, /* * return null immediately if relation is empty */ - if (scan->rs_nblocks == 0) + if (scan->rs_nblocks == scan->rs_lowpage) { Assert(!BufferIsValid(scan->rs_cbuf)); tuple->t_data = NULL; @@ -397,7 +400,7 @@ heapgettup(HeapScanDesc scan, */ scan->rs_syncscan = false; /* start from last page of the scan */ - if (scan->rs_startblock > 0) + if (scan->rs_startblock > scan->rs_lowpage) page = scan->rs_startblock - 1; else page = scan->rs_nblocks - 1; @@ -522,7 +525,7 @@ heapgettup(HeapScanDesc scan, if (backward) { finished = (page == scan->rs_startblock); - if (page == 0) + if (page == scan->rs_lowpage) page = scan->rs_nblocks; page--; } @@ -530,7 +533,7 @@ heapgettup(HeapScanDesc scan, { page++; if (page >= scan->rs_nblocks) - page = 0; + page = scan->rs_lowpage; finished = (page == scan->rs_startblock); /* @@ -1202,6 +1205,7 @@ heap_beginscan_internal(Relation relation, Snapshot snapshot, scan->rs_strategy = NULL; /* set in initscan */ scan->rs_allow_strat = allow_strat; scan->rs_allow_sync = allow_sync; + scan->rs_lowpage = RelationHasMetapage(relation) ? METAPAGE_BLKNO + 1 : 0; /* * we can use page-at-a-time mode if it's an MVCC-safe snapshot diff --git a/src/include/access/metapage.h b/src/include/access/metapage.h index 5f7450036a..65c68bdabd 100644 --- a/src/include/access/metapage.h +++ b/src/include/access/metapage.h @@ -78,6 +78,6 @@ extern RelationMetapage RelationGetMetadata(Relation rel); * Useful macros. */ #define RelationHasMetapage(relation) \ - (RelationGetMetadata((rel))->rmp_version != 0) + (RelationGetMetadata((relation))->rmp_version != 0) #endif /* METAPAGE_H */ diff --git a/src/include/access/relscan.h b/src/include/access/relscan.h index 2e967e1d59..442110e481 100644 --- a/src/include/access/relscan.h +++ b/src/include/access/relscan.h @@ -33,7 +33,8 @@ typedef struct HeapScanDescData bool rs_allow_sync; /* allow or disallow use of syncscan */ /* state set up at initscan time */ - BlockNumber rs_nblocks; /* number of blocks to scan */ + BlockNumber rs_lowpage; /* lowest page number to scan */ + BlockNumber rs_nblocks; /* highest page to scan, plus one */ BlockNumber rs_startblock; /* block # to start at */ BufferAccessStrategy rs_strategy; /* access strategy for reads */ bool rs_syncscan; /* report location to syncscan logic? */