]> granicus.if.org Git - postgresql/blobdiff - src/backend/catalog/storage.c
Update copyright for 2016
[postgresql] / src / backend / catalog / storage.c
index 671aaff133a25a3969604081d0b1570de4d02988..fe68c998e8de130c0fb446e22a4090f5c7aca66b 100644 (file)
@@ -3,7 +3,7 @@
  * storage.c
  *       code to create and destroy physical storage for relations
  *
- * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
 
 #include "access/visibilitymap.h"
 #include "access/xact.h"
+#include "access/xlog.h"
+#include "access/xloginsert.h"
 #include "access/xlogutils.h"
 #include "catalog/catalog.h"
 #include "catalog/storage.h"
+#include "catalog/storage_xlog.h"
 #include "storage/freespace.h"
 #include "storage/smgr.h"
 #include "utils/memutils.h"
@@ -34,7 +37,7 @@
  * that have been created or deleted in the current transaction.  When
  * a relation is created, we create the physical file immediately, but
  * remember it so that we can delete the file again if the current
- * transaction is aborted.     Conversely, a deletion request is NOT
+ * transaction is aborted.  Conversely, a deletion request is NOT
  * executed immediately, but is just entered in the list.  When and if
  * the transaction commits, we can delete the physical file.
  *
@@ -60,29 +63,6 @@ typedef struct PendingRelDelete
 
 static PendingRelDelete *pendingDeletes = NULL; /* head of linked list */
 
-/*
- * Declarations for smgr-related XLOG records
- *
- * Note: we log file creation and truncation here, but logging of deletion
- * actions is handled by xact.c, because it is part of transaction commit.
- */
-
-/* XLOG gives us high 4 bits */
-#define XLOG_SMGR_CREATE       0x10
-#define XLOG_SMGR_TRUNCATE     0x20
-
-typedef struct xl_smgr_create
-{
-       RelFileNode rnode;
-} xl_smgr_create;
-
-typedef struct xl_smgr_truncate
-{
-       BlockNumber blkno;
-       RelFileNode rnode;
-} xl_smgr_truncate;
-
-
 /*
  * RelationCreateStorage
  *             Create physical storage for a relation.
@@ -98,9 +78,6 @@ void
 RelationCreateStorage(RelFileNode rnode, char relpersistence)
 {
        PendingRelDelete *pending;
-       XLogRecPtr      lsn;
-       XLogRecData rdata;
-       xl_smgr_create xlrec;
        SMgrRelation srel;
        BackendId       backend;
        bool            needs_wal;
@@ -111,32 +88,24 @@ RelationCreateStorage(RelFileNode rnode, char relpersistence)
                        backend = MyBackendId;
                        needs_wal = false;
                        break;
+               case RELPERSISTENCE_UNLOGGED:
+                       backend = InvalidBackendId;
+                       needs_wal = false;
+                       break;
                case RELPERSISTENCE_PERMANENT:
                        backend = InvalidBackendId;
                        needs_wal = true;
                        break;
                default:
                        elog(ERROR, "invalid relpersistence: %c", relpersistence);
-                       return;                 /* placate compiler */
+                       return;                         /* placate compiler */
        }
 
        srel = smgropen(rnode, backend);
        smgrcreate(srel, MAIN_FORKNUM, false);
 
        if (needs_wal)
-       {
-               /*
-                * Make an XLOG entry reporting the file creation.
-                */
-               xlrec.rnode = rnode;
-
-               rdata.data = (char *) &xlrec;
-               rdata.len = sizeof(xlrec);
-               rdata.buffer = InvalidBuffer;
-               rdata.next = NULL;
-
-               lsn = XLogInsert(RM_SMGR_ID, XLOG_SMGR_CREATE, &rdata);
-       }
+               log_smgrcreate(&srel->smgr_rnode.node, MAIN_FORKNUM);
 
        /* Add the relation to the list of stuff to delete at abort */
        pending = (PendingRelDelete *)
@@ -149,6 +118,25 @@ RelationCreateStorage(RelFileNode rnode, char relpersistence)
        pendingDeletes = pending;
 }
 
+/*
+ * Perform XLogInsert of an XLOG_SMGR_CREATE record to WAL.
+ */
+void
+log_smgrcreate(RelFileNode *rnode, ForkNumber forkNum)
+{
+       xl_smgr_create xlrec;
+
+       /*
+        * Make an XLOG entry reporting the file creation.
+        */
+       xlrec.rnode = *rnode;
+       xlrec.forkNum = forkNum;
+
+       XLogBeginInsert();
+       XLogRegisterData((char *) &xlrec, sizeof(xlrec));
+       XLogInsert(RM_SMGR_ID, XLOG_SMGR_CREATE | XLR_SPECIAL_REL_UPDATE);
+}
+
 /*
  * RelationDropStorage
  *             Schedule unlinking of physical storage at transaction commit.
@@ -193,10 +181,13 @@ RelationDropStorage(Relation rel)
  * The relation mapper fixes this by telling us to not delete such relations
  * after all as part of its commit.
  *
+ * We also use this to reuse an old build of an index during ALTER TABLE, this
+ * time removing the delete-at-commit entry.
+ *
  * No-op if the relation is not among those scheduled for deletion.
  */
 void
-RelationPreserveStorage(RelFileNode rnode)
+RelationPreserveStorage(RelFileNode rnode, bool atCommit)
 {
        PendingRelDelete *pending;
        PendingRelDelete *prev;
@@ -206,11 +197,9 @@ RelationPreserveStorage(RelFileNode rnode)
        for (pending = pendingDeletes; pending != NULL; pending = next)
        {
                next = pending->next;
-               if (RelFileNodeEquals(rnode, pending->relnode))
+               if (RelFileNodeEquals(rnode, pending->relnode)
+                       && pending->atCommit == atCommit)
                {
-                       /* we should only find delete-on-abort entries, else trouble */
-                       if (pending->atCommit)
-                               elog(ERROR, "cannot preserve a delete-on-commit relation");
                        /* unlink and delete list entry */
                        if (prev)
                                prev->next = next;
@@ -275,18 +264,16 @@ RelationTruncate(Relation rel, BlockNumber nblocks)
                 * Make an XLOG entry reporting the file truncation.
                 */
                XLogRecPtr      lsn;
-               XLogRecData rdata;
                xl_smgr_truncate xlrec;
 
                xlrec.blkno = nblocks;
                xlrec.rnode = rel->rd_node;
 
-               rdata.data = (char *) &xlrec;
-               rdata.len = sizeof(xlrec);
-               rdata.buffer = InvalidBuffer;
-               rdata.next = NULL;
+               XLogBeginInsert();
+               XLogRegisterData((char *) &xlrec, sizeof(xlrec));
 
-               lsn = XLogInsert(RM_SMGR_ID, XLOG_SMGR_TRUNCATE, &rdata);
+               lsn = XLogInsert(RM_SMGR_ID,
+                                                XLOG_SMGR_TRUNCATE | XLR_SPECIAL_REL_UPDATE);
 
                /*
                 * Flush, because otherwise the truncation of the main relation might
@@ -321,6 +308,10 @@ smgrDoPendingDeletes(bool isCommit)
        PendingRelDelete *pending;
        PendingRelDelete *prev;
        PendingRelDelete *next;
+       int                     nrels = 0,
+                               i = 0,
+                               maxrels = 0;
+       SMgrRelation *srels = NULL;
 
        prev = NULL;
        for (pending = pendingDeletes; pending != NULL; pending = next)
@@ -342,21 +333,38 @@ smgrDoPendingDeletes(bool isCommit)
                        if (pending->atCommit == isCommit)
                        {
                                SMgrRelation srel;
-                               int                     i;
 
                                srel = smgropen(pending->relnode, pending->backend);
-                               for (i = 0; i <= MAX_FORKNUM; i++)
+
+                               /* allocate the initial array, or extend it, if needed */
+                               if (maxrels == 0)
+                               {
+                                       maxrels = 8;
+                                       srels = palloc(sizeof(SMgrRelation) * maxrels);
+                               }
+                               else if (maxrels <= nrels)
                                {
-                                       if (smgrexists(srel, i))
-                                               smgrdounlink(srel, i, false);
+                                       maxrels *= 2;
+                                       srels = repalloc(srels, sizeof(SMgrRelation) * maxrels);
                                }
-                               smgrclose(srel);
+
+                               srels[nrels++] = srel;
                        }
                        /* must explicitly free the list entry */
                        pfree(pending);
                        /* prev does not change */
                }
        }
+
+       if (nrels > 0)
+       {
+               smgrdounlinkall(srels, nrels, false);
+
+               for (i = 0; i < nrels; i++)
+                       smgrclose(srels[i]);
+
+               pfree(srels);
+       }
 }
 
 /*
@@ -465,12 +473,13 @@ AtSubAbort_smgr(void)
 }
 
 void
-smgr_redo(XLogRecPtr lsn, XLogRecord *record)
+smgr_redo(XLogReaderState *record)
 {
-       uint8           info = record->xl_info & ~XLR_INFO_MASK;
+       XLogRecPtr      lsn = record->EndRecPtr;
+       uint8           info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
 
        /* Backup blocks are not used in smgr records */
-       Assert(!(record->xl_info & XLR_BKP_BLOCK_MASK));
+       Assert(!XLogRecHasAnyBlockRefs(record));
 
        if (info == XLOG_SMGR_CREATE)
        {
@@ -478,7 +487,7 @@ smgr_redo(XLogRecPtr lsn, XLogRecord *record)
                SMgrRelation reln;
 
                reln = smgropen(xlrec->rnode, InvalidBackendId);
-               smgrcreate(reln, MAIN_FORKNUM, true);
+               smgrcreate(reln, xlrec->forkNum, true);
        }
        else if (info == XLOG_SMGR_TRUNCATE)
        {
@@ -491,11 +500,28 @@ smgr_redo(XLogRecPtr lsn, XLogRecord *record)
                /*
                 * Forcibly create relation if it doesn't exist (which suggests that
                 * it was dropped somewhere later in the WAL sequence).  As in
-                * XLogOpenRelation, we prefer to recreate the rel and replay the log
-                * as best we can until the drop is seen.
+                * XLogReadBufferForRedo, we prefer to recreate the rel and replay the
+                * log as best we can until the drop is seen.
                 */
                smgrcreate(reln, MAIN_FORKNUM, true);
 
+               /*
+                * Before we perform the truncation, update minimum recovery point to
+                * cover this WAL record. Once the relation is truncated, there's no
+                * going back. The buffer manager enforces the WAL-first rule for
+                * normal updates to relation files, so that the minimum recovery
+                * point is always updated before the corresponding change in the data
+                * file is flushed to disk. We have to do the same manually here.
+                *
+                * Doing this before the truncation means that if the truncation fails
+                * for some reason, you cannot start up the system even after restart,
+                * until you fix the underlying situation so that the truncation will
+                * succeed. Alternatively, we could update the minimum recovery point
+                * after truncation, but that would leave a small window where the
+                * WAL-first rule could be violated.
+                */
+               XLogFlush(lsn);
+
                smgrtruncate(reln, MAIN_FORKNUM, xlrec->blkno);
 
                /* Also tell xlogutils.c about it */
@@ -514,29 +540,3 @@ smgr_redo(XLogRecPtr lsn, XLogRecord *record)
        else
                elog(PANIC, "smgr_redo: unknown op code %u", info);
 }
-
-void
-smgr_desc(StringInfo buf, uint8 xl_info, char *rec)
-{
-       uint8           info = xl_info & ~XLR_INFO_MASK;
-
-       if (info == XLOG_SMGR_CREATE)
-       {
-               xl_smgr_create *xlrec = (xl_smgr_create *) rec;
-               char       *path = relpathperm(xlrec->rnode, MAIN_FORKNUM);
-
-               appendStringInfo(buf, "file create: %s", path);
-               pfree(path);
-       }
-       else if (info == XLOG_SMGR_TRUNCATE)
-       {
-               xl_smgr_truncate *xlrec = (xl_smgr_truncate *) rec;
-               char       *path = relpathperm(xlrec->rnode, MAIN_FORKNUM);
-
-               appendStringInfo(buf, "file truncate: %s to %u blocks", path,
-                                                xlrec->blkno);
-               pfree(path);
-       }
-       else
-               appendStringInfo(buf, "UNKNOWN");
-}