Heap metapages.
authorRobert Haas <rhaas@postgresql.org>
Thu, 14 Jun 2012 03:57:40 +0000 (23:57 -0400)
committerRobert Haas <rhaas@postgresql.org>
Thu, 14 Jun 2012 14:33:06 +0000 (10:33 -0400)
Probably handles rewrites incorrectly, and fails regression tests, but some
of those failures are bogus, and many are due to costing differences.
But, hey, at least it no longer crashes.

src/backend/access/heap/heapam.c
src/backend/access/heap/hio.c
src/backend/catalog/heap.c
src/backend/commands/sequence.c
src/backend/commands/tablecmds.c
src/backend/commands/vacuumlazy.c
src/backend/storage/freespace/freespace.c
src/backend/utils/cache/relcache.c
src/include/access/metapage.h
src/include/catalog/heap.h

index 5ff70f2af2d8926a8e855c6bc6392d9246a30574..8c761e9767e789b6e30572be5b0e4d3f2cdafc72 100644 (file)
@@ -1206,7 +1206,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;
+       scan->rs_lowpage = RelationFirstNonMetapage(relation);
 
        /*
         * we can use page-at-a-time mode if it's an MVCC-safe snapshot
index 19a34923c7a74ddbf09d073ffe09f7cb5893cf80..ca6eed4aa9f98717164e1a6feb9ebeac592ffb11 100644 (file)
@@ -17,6 +17,7 @@
 
 #include "access/heapam.h"
 #include "access/hio.h"
+#include "access/metapage.h"
 #include "access/visibilitymap.h"
 #include "storage/bufmgr.h"
 #include "storage/freespace.h"
@@ -290,13 +291,16 @@ RelationGetBufferForTuple(Relation relation, Size len,
                {
                        BlockNumber nblocks = RelationGetNumberOfBlocks(relation);
 
-                       if (nblocks > 0)
+                       if (nblocks > RelationFirstNonMetapage(relation))
                                targetBlock = nblocks - 1;
                }
        }
 
        while (targetBlock != InvalidBlockNumber)
        {
+               /* Make sure we don't insert into the metapage. */
+               Assert(targetBlock != METAPAGE_BLKNO || !RelationHasMetapage(relation));
+
                /*
                 * Read and exclusive-lock the target block, as well as the other
                 * block if one was given, taking suitable care with lock ordering and
index cb162810f7e711c4d35feee1b20f8e81de200127..acce848f1567035445a16ac1214a47f333ff613b 100644 (file)
@@ -29,6 +29,7 @@
  */
 #include "postgres.h"
 
+#include "access/metapage.h"
 #include "access/sysattr.h"
 #include "access/transam.h"
 #include "access/xact.h"
@@ -57,6 +58,7 @@
 #include "parser/parse_collate.h"
 #include "parser/parse_expr.h"
 #include "parser/parse_relation.h"
+#include "storage/bufmgr.h"
 #include "storage/predicate.h"
 #include "storage/smgr.h"
 #include "utils/acl.h"
@@ -303,6 +305,7 @@ heap_create(const char *relname,
        {
                RelationOpenSmgr(rel);
                RelationCreateStorage(rel->rd_node, relpersistence);
+               heap_create_storage(rel);
        }
 
        return rel;
@@ -1267,12 +1270,6 @@ heap_create_with_catalog(const char *relname,
        if (oncommit != ONCOMMIT_NOOP)
                register_on_commit_action(relid, oncommit);
 
-       if (relpersistence == RELPERSISTENCE_UNLOGGED)
-       {
-               Assert(relkind == RELKIND_RELATION || relkind == RELKIND_TOASTVALUE);
-               heap_create_init_fork(new_rel_desc);
-       }
-
        /*
         * ok, the relation has been cataloged, so close our relations and return
         * the OID of the newly created relation.
@@ -1284,20 +1281,50 @@ heap_create_with_catalog(const char *relname,
 }
 
 /*
- * Set up an init fork for an unlogged table so that it can be correctly
- * reinitialized on restart.  Since we're going to do an immediate sync, we
- * only need to xlog this if archiving or streaming is enabled.  And the
- * immediate sync is required, because otherwise there's no guarantee that
- * this will hit the disk before the next checkpoint moves the redo pointer.
+ * Create storage for a new heap relation.
+ *
+ * This creates the physical file and inserts the metapage.  If the relation
+ * is unlogged, we do the same for the init fork as well.
  */
 void
-heap_create_init_fork(Relation rel)
+heap_create_storage(Relation rel)
 {
-       RelationOpenSmgr(rel);
-       smgrcreate(rel->rd_smgr, INIT_FORKNUM, false);
-       if (XLogIsNeeded())
-               log_smgrcreate(&rel->rd_smgr->smgr_rnode.node, INIT_FORKNUM);
-       smgrimmedsync(rel->rd_smgr, INIT_FORKNUM);
+       Buffer          metabuffer;
+       Page            metapage;
+
+       /* Write metapage. */
+       metabuffer = ReadBufferExtended(rel, MAIN_FORKNUM, P_NEW, RBM_ZERO, NULL);
+       metapage = BufferGetPage(metabuffer);
+       Assert(BufferGetBlockNumber(metabuffer) == METAPAGE_BLKNO);
+       LockBuffer(metabuffer, BUFFER_LOCK_EXCLUSIVE);
+       START_CRIT_SECTION();
+       PageInit(metapage, BLCKSZ, 0);
+       MetapageInit(rel, metapage);
+       MarkBufferDirty(metabuffer);
+       if (RelationNeedsWAL(rel))
+               log_newpage_buffer(metabuffer);
+       END_CRIT_SECTION();
+       UnlockReleaseBuffer(metabuffer);
+
+       /*
+        * If this relation is unlogged, set up an init fork so that it can be
+        * correctly reinitialized on restart.
+        */
+       if (rel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED)
+       {
+               smgrcreate(rel->rd_smgr, INIT_FORKNUM, false);
+               metabuffer = ReadBufferExtended(rel, INIT_FORKNUM, P_NEW, RBM_ZERO,
+                                                                               NULL);
+               Assert(BufferGetBlockNumber(metabuffer) == METAPAGE_BLKNO);
+               LockBuffer(metabuffer, BUFFER_LOCK_EXCLUSIVE);
+               START_CRIT_SECTION();
+               PageInit(metapage, BLCKSZ, 0);
+               MetapageInit(rel, metapage);
+               MarkBufferDirty(metabuffer);
+               log_newpage_buffer(metabuffer);
+               END_CRIT_SECTION();
+               UnlockReleaseBuffer(metabuffer);
+       }
 }
 
 /*
index 34b74f6c3844a3a172cd660357f8ccbc48f57f3c..fb026f8b03c4c5deaf0a92e308f98530bb99d440 100644 (file)
@@ -14,6 +14,7 @@
  */
 #include "postgres.h"
 
+#include "access/metapage.h"
 #include "access/transam.h"
 #include "access/xlogutils.h"
 #include "catalog/dependency.h"
@@ -314,7 +315,7 @@ fill_seq_with_data(Relation rel, HeapTuple tuple)
        /* Initialize first page of relation with special magic number */
 
        buf = ReadBuffer(rel, P_NEW);
-       Assert(BufferGetBlockNumber(buf) == 0);
+       Assert(BufferGetBlockNumber(buf) == RelationFirstNonMetapage(rel));
 
        page = BufferGetPage(buf);
 
@@ -323,7 +324,7 @@ fill_seq_with_data(Relation rel, HeapTuple tuple)
        sm->magic = SEQ_MAGIC;
 
        /* hack: ensure heap_insert will insert on the just-created page */
-       RelationSetTargetBlock(rel, 0);
+       RelationSetTargetBlock(rel, BufferGetBlockNumber(buf));
 
        /* Now insert sequence tuple */
        simple_heap_insert(rel, tuple);
@@ -1076,7 +1077,7 @@ read_info(SeqTable elm, Relation rel, Buffer *buf)
        sequence_magic *sm;
        Form_pg_sequence seq;
 
-       *buf = ReadBuffer(rel, 0);
+       *buf = ReadBuffer(rel, RelationFirstNonMetapage(rel));
        LockBuffer(*buf, BUFFER_LOCK_EXCLUSIVE);
 
        page = BufferGetPage(*buf);
index 5c69cfb85a2e1b5b961a252780b2024f33c6a1dd..70c5b8cc0ebe3710c41745b66e5fb2a42a2b5fa8 100644 (file)
@@ -1155,8 +1155,7 @@ ExecuteTruncate(TruncateStmt *stmt)
                         * deletion at commit.
                         */
                        RelationSetNewRelfilenode(rel, RecentXmin);
-                       if (rel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED)
-                               heap_create_init_fork(rel);
+                       heap_create_storage(rel);
 
                        heap_relid = RelationGetRelid(rel);
                        toast_relid = rel->rd_rel->reltoastrelid;
@@ -1168,8 +1167,7 @@ ExecuteTruncate(TruncateStmt *stmt)
                        {
                                rel = relation_open(toast_relid, AccessExclusiveLock);
                                RelationSetNewRelfilenode(rel, RecentXmin);
-                               if (rel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED)
-                                       heap_create_init_fork(rel);
+                               heap_create_storage(rel);
                                heap_close(rel, NoLock);
                        }
 
index 5e902211649e2d0526664470054e015557098dab..104bacc8c7e9880942b8a8bd7d5991b717ec533a 100644 (file)
@@ -39,6 +39,7 @@
 
 #include "access/genam.h"
 #include "access/heapam.h"
+#include "access/metapage.h"
 #include "access/transam.h"
 #include "access/visibilitymap.h"
 #include "catalog/storage.h"
@@ -360,7 +361,8 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
                           Relation *Irel, int nindexes, bool scan_all)
 {
        BlockNumber nblocks,
-                               blkno;
+                               blkno,
+                               startblock;
        HeapTupleData tuple;
        char       *relname;
        BlockNumber empty_pages,
@@ -398,6 +400,8 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
 
        lazy_space_alloc(vacrelstats, nblocks);
 
+       startblock = RelationFirstNonMetapage(onerel);
+
        /*
         * We want to skip pages that don't require vacuuming according to the
         * visibility map, but only when we can skip at least SKIP_PAGES_THRESHOLD
@@ -429,7 +433,7 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
         * them.  If we make the reverse mistake and vacuum a page unnecessarily,
         * it'll just be a no-op.
         */
-       for (next_not_all_visible_block = 0;
+       for (next_not_all_visible_block = startblock;
                 next_not_all_visible_block < nblocks;
                 next_not_all_visible_block++)
        {
@@ -442,7 +446,7 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
        else
                skipping_all_visible_blocks = false;
 
-       for (blkno = 0; blkno < nblocks; blkno++)
+       for (blkno = startblock; blkno < nblocks; blkno++)
        {
                Buffer          buf;
                Page            page;
index 7840adb3501c8b4ab83ef9572c8ed8e01473ce11..e6f6472df18bad4ccf2c1a34c7f5584d2b49cb21 100644 (file)
@@ -24,6 +24,7 @@
 #include "postgres.h"
 
 #include "access/htup.h"
+#include "access/metapage.h"
 #include "access/xlogutils.h"
 #include "miscadmin.h"
 #include "storage/freespace.h"
@@ -182,6 +183,9 @@ RecordPageWithFreeSpace(Relation rel, BlockNumber heapBlk, Size spaceAvail)
        FSMAddress      addr;
        uint16          slot;
 
+       /* No free space in the metablock! */
+       Assert(heapBlk != METAPAGE_BLKNO || !RelationHasMetapage(rel));
+
        /* Get the location of the FSM byte representing the heap block */
        addr = fsm_get_location(heapBlk, &slot);
 
index 685955e58b31dc15026fa438dbf89f9aecc57814..b0253755f101c6d671348bf98679d7ac37bef941 100644 (file)
@@ -2588,9 +2588,7 @@ RelationBuildLocalRelation(const char *relname,
 
        RelationInitPhysicalAddr(rel);
 
-       /* XXX: Not for heaps yet. */
-       if (relkind == RELKIND_INDEX)
-               RelationBuildMetadata(rel);
+       RelationBuildMetadata(rel);
 
        /*
         * Okay to insert into the relcache hash tables.
index a119dc4dc6fd6acd6fa94a0b28f6e5554df97881..2ce45b3cf24a4532b7687253a7de9cd81da79720 100644 (file)
@@ -80,5 +80,7 @@ extern RelationMetapage RelationGetMetadata(Relation rel);
  */
 #define RelationHasMetapage(relation) \
        (RelationGetMetadata((relation))->rmp_version != 0)
+#define RelationFirstNonMetapage(relation) \
+       (RelationHasMetapage((relation)) ? 1 : 0)
 
 #endif   /* METAPAGE_H */
index adb7ea2a1e08cc00766f8693e5840f7481b649aa..653ee6ad410dd72977d378a61b9377bddbc1e7b8 100644 (file)
@@ -67,7 +67,7 @@ extern Oid heap_create_with_catalog(const char *relname,
                                                 bool use_user_acl,
                                                 bool allow_system_table_mods);
 
-extern void heap_create_init_fork(Relation rel);
+extern void heap_create_storage(Relation rel);
 
 extern void heap_drop_with_catalog(Oid relid);