Try to make the world safe for heap metapages.
authorRobert Haas <[email protected]>
Wed, 13 Jun 2012 02:19:28 +0000 (22:19 -0400)
committerRobert Haas <[email protected]>
Thu, 14 Jun 2012 14:33:05 +0000 (10:33 -0400)
src/backend/access/common/metapage.c
src/backend/access/heap/heapam.c
src/include/access/metapage.h
src/include/access/relscan.h

index 3606a133ab91ad289c02a1f2ffa4926eb42b8c81..b143c55e7756774339ecc0e131fb6edb2110a6ff 100644 (file)
@@ -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;
index f28026be0fb68f0059f1b1778fa80757a32e915d..31807d82415a04bc073aacbc94e3220ee8f65249 100644 (file)
@@ -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
index 5f7450036a09daf91c22b36ec5e983742cda6c0c..65c68bdabd6c5c0d4aa5d7cc808d1a2e691dea3e 100644 (file)
@@ -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 */
index 2e967e1d597ef44b1057412d665ae88cfce522fd..442110e481c9f23020b398bc50172fd42fe615d9 100644 (file)
@@ -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? */