When cloning template0 (or other fully-frozen databases), set the new
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 12 Mar 2005 21:33:55 +0000 (21:33 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 12 Mar 2005 21:33:55 +0000 (21:33 +0000)
database's datallowconn and datfrozenxid to the current transaction ID
instead of copying the source database's values.  This is OK because we
assume the source DB contains no normal transaction IDs whatsoever.
This keeps VACUUM from immediately starting to complain about unvacuumed
databases in the situation where we are more than 2 billion transactions
out from the XID stamp of template0.  Per discussion with Milen Radev
(although his complaint turned out to be due to something else, but the
problem is real anyway).

src/backend/commands/dbcommands.c

index a076ff4c9cdc96b1d99ccf4b72ad47b3af1b5eae..f3327b1fb2fa4e9e68161a23fb84b45944e30cd7 100644 (file)
@@ -15,7 +15,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.153 2005/03/12 21:11:50 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.154 2005/03/12 21:33:55 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -54,7 +54,8 @@
 
 /* non-export function prototypes */
 static bool get_db_info(const char *name, Oid *dbIdP, int4 *ownerIdP,
-                       int *encodingP, bool *dbIsTemplateP, Oid *dbLastSysOidP,
+                       int *encodingP, bool *dbIsTemplateP, bool *dbAllowConnP,
+                       Oid *dbLastSysOidP,
                        TransactionId *dbVacuumXidP, TransactionId *dbFrozenXidP,
                        Oid *dbTablespace);
 static bool have_createdb_privilege(void);
@@ -73,6 +74,7 @@ createdb(const CreatedbStmt *stmt)
        AclId           src_owner;
        int                     src_encoding;
        bool            src_istemplate;
+       bool            src_allowconn;
        Oid                     src_lastsysoid;
        TransactionId src_vacuumxid;
        TransactionId src_frozenxid;
@@ -217,7 +219,8 @@ createdb(const CreatedbStmt *stmt)
         * idea, so accept possibility of race to create.  We will check again
         * after we grab the exclusive lock.
         */
-       if (get_db_info(dbname, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL))
+       if (get_db_info(dbname, NULL, NULL, NULL,
+                                       NULL, NULL, NULL, NULL, NULL, NULL))
                ereport(ERROR,
                                (errcode(ERRCODE_DUPLICATE_DATABASE),
                                 errmsg("database \"%s\" already exists", dbname)));
@@ -229,7 +232,7 @@ createdb(const CreatedbStmt *stmt)
                dbtemplate = "template1";               /* Default template database name */
 
        if (!get_db_info(dbtemplate, &src_dboid, &src_owner, &src_encoding,
-                                        &src_istemplate, &src_lastsysoid,
+                                        &src_istemplate, &src_allowconn, &src_lastsysoid,
                                         &src_vacuumxid, &src_frozenxid, &src_deftablespace))
                ereport(ERROR,
                                (errcode(ERRCODE_UNDEFINED_DATABASE),
@@ -328,6 +331,16 @@ createdb(const CreatedbStmt *stmt)
                /* Note there is no additional permission check in this path */
        }
 
+       /*
+        * Normally we mark the new database with the same datvacuumxid and
+        * datfrozenxid as the source.  However, if the source is not allowing
+        * connections then we assume it is fully frozen, and we can set the
+        * current transaction ID as the xid limits.  This avoids immediately
+        * starting to generate warnings after cloning template0.
+        */
+       if (!src_allowconn)
+               src_vacuumxid = src_frozenxid = GetCurrentTransactionId();
+
        /*
         * Preassign OID for pg_database tuple, so that we can compute db
         * path.
@@ -455,7 +468,8 @@ createdb(const CreatedbStmt *stmt)
        pg_database_rel = heap_openr(DatabaseRelationName, ExclusiveLock);
 
        /* Check to see if someone else created same DB name meanwhile. */
-       if (get_db_info(dbname, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL))
+       if (get_db_info(dbname, NULL, NULL, NULL,
+                                       NULL, NULL, NULL, NULL, NULL, NULL))
        {
                /* Don't hold lock while doing recursive remove */
                heap_close(pg_database_rel, ExclusiveLock);
@@ -552,7 +566,7 @@ dropdb(const char *dbname)
        pgdbrel = heap_openr(DatabaseRelationName, ExclusiveLock);
 
        if (!get_db_info(dbname, &db_id, &db_owner, NULL,
-                                        &db_istemplate, NULL, NULL, NULL, NULL))
+                                        &db_istemplate, NULL, NULL, NULL, NULL, NULL))
                ereport(ERROR,
                                (errcode(ERRCODE_UNDEFINED_DATABASE),
                                 errmsg("database \"%s\" does not exist", dbname)));
@@ -936,7 +950,8 @@ AlterDatabaseOwner(const char *dbname, AclId newOwnerSysId)
 
 static bool
 get_db_info(const char *name, Oid *dbIdP, int4 *ownerIdP,
-                       int *encodingP, bool *dbIsTemplateP, Oid *dbLastSysOidP,
+                       int *encodingP, bool *dbIsTemplateP, bool *dbAllowConnP,
+                       Oid *dbLastSysOidP,
                        TransactionId *dbVacuumXidP, TransactionId *dbFrozenXidP,
                        Oid *dbTablespace)
 {
@@ -978,6 +993,9 @@ get_db_info(const char *name, Oid *dbIdP, int4 *ownerIdP,
                /* allowed as template? */
                if (dbIsTemplateP)
                        *dbIsTemplateP = dbform->datistemplate;
+               /* allowing connections? */
+               if (dbAllowConnP)
+                       *dbAllowConnP = dbform->datallowconn;
                /* last system OID used in database */
                if (dbLastSysOidP)
                        *dbLastSysOidP = dbform->datlastsysoid;