]> granicus.if.org Git - postgresql/blobdiff - src/backend/utils/init/flatfiles.c
Message style improvements
[postgresql] / src / backend / utils / init / flatfiles.c
index 9906682c320474bea39ec4c86e48240d63361143..8867ec3e015fc520582de52978bc42821fc99b3d 100644 (file)
  * a way that this is OK.
  *
  *
- * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/backend/utils/init/flatfiles.c,v 1.15 2005/10/15 02:49:33 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/init/flatfiles.c,v 1.21 2006/07/14 14:52:25 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -33,7 +33,9 @@
 #include <unistd.h>
 
 #include "access/heapam.h"
+#include "access/transam.h"
 #include "access/twophase_rmgr.h"
+#include "access/xact.h"
 #include "catalog/pg_auth_members.h"
 #include "catalog/pg_authid.h"
 #include "catalog/pg_database.h"
 #include "miscadmin.h"
 #include "storage/fd.h"
 #include "storage/pmsignal.h"
-#include "utils/acl.h"
 #include "utils/builtins.h"
 #include "utils/flatfiles.h"
 #include "utils/resowner.h"
-#include "utils/syscache.h"
 
 
 /* Actual names of the flat files (within $PGDATA) */
@@ -163,7 +163,7 @@ name_okay(const char *str)
 /*
  * write_database_file: update the flat database file
  *
- * A side effect is to determine the oldest database's datfrozenxid
+ * A side effect is to determine the oldest database's datminxid
  * so we can set or update the XID wrap limit.
  */
 static void
@@ -177,7 +177,7 @@ write_database_file(Relation drel)
        HeapScanDesc scan;
        HeapTuple       tuple;
        NameData        oldest_datname;
-       TransactionId oldest_datfrozenxid = InvalidTransactionId;
+       TransactionId oldest_datminxid = InvalidTransactionId;
 
        /*
         * Create a temporary filename to be renamed later.  This prevents the
@@ -208,27 +208,27 @@ write_database_file(Relation drel)
                char       *datname;
                Oid                     datoid;
                Oid                     dattablespace;
-               TransactionId datfrozenxid,
+               TransactionId datminxid,
                                        datvacuumxid;
 
                datname = NameStr(dbform->datname);
                datoid = HeapTupleGetOid(tuple);
                dattablespace = dbform->dattablespace;
-               datfrozenxid = dbform->datfrozenxid;
+               datminxid = dbform->datminxid;
                datvacuumxid = dbform->datvacuumxid;
 
                /*
-                * Identify the oldest datfrozenxid, ignoring databases that are not
+                * Identify the oldest datminxid, ignoring databases that are not
                 * connectable (we assume they are safely frozen).      This must match
                 * the logic in vac_truncate_clog() in vacuum.c.
                 */
                if (dbform->datallowconn &&
-                       TransactionIdIsNormal(datfrozenxid))
+                       TransactionIdIsNormal(datminxid))
                {
-                       if (oldest_datfrozenxid == InvalidTransactionId ||
-                               TransactionIdPrecedes(datfrozenxid, oldest_datfrozenxid))
+                       if (oldest_datminxid == InvalidTransactionId ||
+                               TransactionIdPrecedes(datminxid, oldest_datminxid))
                        {
-                               oldest_datfrozenxid = datfrozenxid;
+                               oldest_datminxid = datminxid;
                                namestrcpy(&oldest_datname, datname);
                        }
                }
@@ -244,14 +244,14 @@ write_database_file(Relation drel)
                }
 
                /*
-                * The file format is: "dbname" oid tablespace frozenxid vacuumxid
+                * The file format is: "dbname" oid tablespace minxid vacuumxid
                 *
                 * The xids are not needed for backend startup, but are of use to
                 * autovacuum, and might also be helpful for forensic purposes.
                 */
                fputs_quote(datname, fp);
                fprintf(fp, " %u %u %u %u\n",
-                               datoid, dattablespace, datfrozenxid, datvacuumxid);
+                               datoid, dattablespace, datminxid, datvacuumxid);
        }
        heap_endscan(scan);
 
@@ -272,10 +272,10 @@ write_database_file(Relation drel)
                                                tempname, filename)));
 
        /*
-        * Set the transaction ID wrap limit using the oldest datfrozenxid
+        * Set the transaction ID wrap limit using the oldest datminxid
         */
-       if (oldest_datfrozenxid != InvalidTransactionId)
-               SetTransactionIdLimit(oldest_datfrozenxid, &oldest_datname);
+       if (oldest_datminxid != InvalidTransactionId)
+               SetTransactionIdLimit(oldest_datminxid, &oldest_datname);
 }
 
 
@@ -593,8 +593,8 @@ write_auth_file(Relation rel_authid, Relation rel_authmem)
                         * Convert list of role Oids to list of role names. We must do
                         * this before re-sorting auth_info.
                         *
-                        * We skip the first list element (curr_role itself) since there is
-                        * no point in writing that a role is a member of itself.
+                        * We skip the first list element (curr_role itself) since there
+                        * is no point in writing that a role is a member of itself.
                         */
                        for_each_cell(mem, lnext(list_head(roles_list)))
                        {
@@ -768,25 +768,49 @@ AtEOXact_UpdateFlatFiles(bool isCommit)
        CommandCounterIncrement();
 
        /*
-        * We use ExclusiveLock to ensure that only one backend writes the flat
-        * file(s) at a time.  That's sufficient because it's okay to allow plain
-        * reads of the tables in parallel.  There is some chance of a deadlock
-        * here (if we were triggered by a user update of one of the tables, which
-        * likely won't have gotten a strong enough lock), so get the locks we
-        * need before writing anything.
+        * Open and lock the needed catalog(s).
         *
-        * For writing the auth file, it's sufficient to ExclusiveLock pg_authid; we
-        * take just regular AccessShareLock on pg_auth_members.
+        * Even though we only need AccessShareLock, this could theoretically fail
+        * due to deadlock.  In practice, however, our transaction already holds
+        * RowExclusiveLock or better (it couldn't have updated the catalog
+        * without such a lock).  This implies that dbcommands.c and other places
+        * that force flat-file updates must not follow the common practice of
+        * dropping catalog locks before commit.
         */
        if (database_file_update_subid != InvalidSubTransactionId)
-               drel = heap_open(DatabaseRelationId, ExclusiveLock);
+               drel = heap_open(DatabaseRelationId, AccessShareLock);
 
        if (auth_file_update_subid != InvalidSubTransactionId)
        {
-               arel = heap_open(AuthIdRelationId, ExclusiveLock);
+               arel = heap_open(AuthIdRelationId, AccessShareLock);
                mrel = heap_open(AuthMemRelationId, AccessShareLock);
        }
 
+       /*
+        * Obtain special locks to ensure that two transactions don't try to write
+        * the same flat file concurrently.  Quite aside from any direct risks of
+        * corrupted output, the winning writer probably wouldn't have seen the
+        * other writer's updates.  By taking a lock and holding it till commit,
+        * we ensure that whichever updater goes second will see the other
+        * updater's changes as committed, and thus the final state of the file
+        * will include all updates.
+        *
+        * We use a lock on "database 0" to protect writing the pg_database flat
+        * file, and a lock on "role 0" to protect the auth file.  This is a bit
+        * ugly but it's not worth inventing any more-general convention.  (Any
+        * two locktags that are never used for anything else would do.)
+        *
+        * This is safe against deadlock as long as these are the very last locks
+        * acquired during the transaction.
+        */
+       if (database_file_update_subid != InvalidSubTransactionId)
+               LockSharedObject(DatabaseRelationId, InvalidOid, 0,
+                                                AccessExclusiveLock);
+
+       if (auth_file_update_subid != InvalidSubTransactionId)
+               LockSharedObject(AuthIdRelationId, InvalidOid, 0,
+                                                AccessExclusiveLock);
+
        /* Okay to write the files */
        if (database_file_update_subid != InvalidSubTransactionId)
        {