]> granicus.if.org Git - postgresql/commitdiff
Make TRUNCATE do truncate-in-place when processing a relation that was created
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 23 Aug 2009 19:23:41 +0000 (19:23 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 23 Aug 2009 19:23:41 +0000 (19:23 +0000)
or previously truncated in the current (sub)transaction.  This is safe since
if the (sub)transaction later rolls back, we'd just discard the rel's current
physical file anyway.  This avoids unreasonable growth in the number of
transient files when a relation is repeatedly truncated.  Per a performance
gripe a couple weeks ago from Todd Cook.

src/backend/catalog/heap.c
src/backend/commands/tablecmds.c
src/include/catalog/heap.h

index 010845536825b3892ee0336647c84260792deaa4..2d97dba701408fca2b0b2d645594689bef3ecc36 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.357 2009/08/02 22:14:52 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.358 2009/08/23 19:23:40 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -2342,18 +2342,9 @@ heap_truncate(List *relids)
        {
                Oid                     rid = lfirst_oid(cell);
                Relation        rel;
-               Oid                     toastrelid;
 
                rel = heap_open(rid, AccessExclusiveLock);
                relations = lappend(relations, rel);
-
-               /* If there is a toast table, add it to the list too */
-               toastrelid = rel->rd_rel->reltoastrelid;
-               if (OidIsValid(toastrelid))
-               {
-                       rel = heap_open(toastrelid, AccessExclusiveLock);
-                       relations = lappend(relations, rel);
-               }
        }
 
        /* Don't allow truncate on tables that are referenced by foreign keys */
@@ -2364,19 +2355,47 @@ heap_truncate(List *relids)
        {
                Relation        rel = lfirst(cell);
 
-               /* Truncate the actual file (and discard buffers) */
-               RelationTruncate(rel, 0);
+               /* Truncate the relation */
+               heap_truncate_one_rel(rel);
 
-               /* If this relation has indexes, truncate the indexes too */
-               RelationTruncateIndexes(rel);
-
-               /*
-                * Close the relation, but keep exclusive lock on it until commit.
-                */
+               /* Close the relation, but keep exclusive lock on it until commit */
                heap_close(rel, NoLock);
        }
 }
 
+/*
+ *      heap_truncate_one_rel
+ *
+ *      This routine deletes all data within the specified relation.
+ *
+ * This is not transaction-safe, because the truncation is done immediately
+ * and cannot be rolled back later.  Caller is responsible for having
+ * checked permissions etc, and must have obtained AccessExclusiveLock.
+ */
+void
+heap_truncate_one_rel(Relation rel)
+{
+       Oid                     toastrelid;
+
+       /* Truncate the actual file (and discard buffers) */
+       RelationTruncate(rel, 0);
+
+       /* If the relation has indexes, truncate the indexes too */
+       RelationTruncateIndexes(rel);
+
+       /* If there is a toast table, truncate that too */
+       toastrelid = rel->rd_rel->reltoastrelid;
+       if (OidIsValid(toastrelid))
+       {
+               Relation        toastrel = heap_open(toastrelid, AccessExclusiveLock);
+
+               RelationTruncate(toastrel, 0);
+               RelationTruncateIndexes(toastrel);
+               /* keep the lock... */
+               heap_close(toastrel, NoLock);
+       }
+}
+
 /*
  * heap_truncate_check_FKs
  *             Check for foreign keys referencing a list of relations that
index 07bc3932003b10e52135319c32f3d1700334433c..a36cbc51aff79f94368a61f2a13635f04d400781 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.297 2009/08/12 23:00:12 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.298 2009/08/23 19:23:41 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -775,6 +775,7 @@ ExecuteTruncate(TruncateStmt *stmt)
        EState     *estate;
        ResultRelInfo *resultRelInfos;
        ResultRelInfo *resultRelInfo;
+       SubTransactionId mySubid;
        ListCell   *cell;
 
        /*
@@ -944,36 +945,58 @@ ExecuteTruncate(TruncateStmt *stmt)
        /*
         * OK, truncate each table.
         */
+       mySubid = GetCurrentSubTransactionId();
+
        foreach(cell, rels)
        {
                Relation        rel = (Relation) lfirst(cell);
-               Oid                     heap_relid;
-               Oid                     toast_relid;
 
                /*
-                * Create a new empty storage file for the relation, and assign it as
-                * the relfilenode value.       The old storage file is scheduled for
-                * deletion at commit.
+                * Normally, we need a transaction-safe truncation here.  However,
+                * if the table was either created in the current (sub)transaction
+                * or has a new relfilenode in the current (sub)transaction, then
+                * we can just truncate it in-place, because a rollback would
+                * cause the whole table or the current physical file to be
+                * thrown away anyway.
                 */
-               setNewRelfilenode(rel, RecentXmin);
-
-               heap_relid = RelationGetRelid(rel);
-               toast_relid = rel->rd_rel->reltoastrelid;
-
-               /*
-                * The same for the toast table, if any.
-                */
-               if (OidIsValid(toast_relid))
+               if (rel->rd_createSubid == mySubid ||
+                       rel->rd_newRelfilenodeSubid == mySubid)
                {
-                       rel = relation_open(toast_relid, AccessExclusiveLock);
-                       setNewRelfilenode(rel, RecentXmin);
-                       heap_close(rel, NoLock);
+                       /* Immediate, non-rollbackable truncation is OK */
+                       heap_truncate_one_rel(rel);
                }
+               else
+               {
+                       Oid                     heap_relid;
+                       Oid                     toast_relid;
 
-               /*
-                * Reconstruct the indexes to match, and we're done.
-                */
-               reindex_relation(heap_relid, true);
+                       /*
+                        * Need the full transaction-safe pushups.
+                        *
+                        * Create a new empty storage file for the relation, and assign it
+                        * as the relfilenode value. The old storage file is scheduled for
+                        * deletion at commit.
+                        */
+                       setNewRelfilenode(rel, RecentXmin);
+
+                       heap_relid = RelationGetRelid(rel);
+                       toast_relid = rel->rd_rel->reltoastrelid;
+
+                       /*
+                        * The same for the toast table, if any.
+                        */
+                       if (OidIsValid(toast_relid))
+                       {
+                               rel = relation_open(toast_relid, AccessExclusiveLock);
+                               setNewRelfilenode(rel, RecentXmin);
+                               heap_close(rel, NoLock);
+                       }
+
+                       /*
+                        * Reconstruct the indexes to match, and we're done.
+                        */
+                       reindex_relation(heap_relid, true);
+               }
        }
 
        /*
index 2d6eb3c34ad392e140c26b2fd94489f70fac1d05..1d7449f1f10d4db075b483e0578af652e5db3c35 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/heap.h,v 1.91 2009/06/11 14:49:09 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/heap.h,v 1.92 2009/08/23 19:23:41 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -62,6 +62,8 @@ extern void heap_drop_with_catalog(Oid relid);
 
 extern void heap_truncate(List *relids);
 
+extern void heap_truncate_one_rel(Relation rel);
+
 extern void heap_truncate_check_FKs(List *relations, bool tempTables);
 
 extern List *heap_truncate_find_FKs(List *relationIds);