OSDN Git Service

Finish up the flat-files project: get rid of GetRawDatabaseInfo() hack
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 26 Feb 2005 18:43:34 +0000 (18:43 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 26 Feb 2005 18:43:34 +0000 (18:43 +0000)
in favor of looking at the flat file copy of pg_database during backend
startup.  This should finally eliminate the various corner cases in which
backend startup fails unexpectedly because it isn't able to distinguish
live and dead tuples in pg_database.  Simplify locking on pg_database
to be similar to the rules used with pg_shadow and pg_group, and eliminate
FlushRelationBuffers operations that were used only to reduce the odds
of failure of GetRawDatabaseInfo.
initdb forced due to addition of a trigger to pg_database.

12 files changed:
src/backend/commands/dbcommands.c
src/backend/commands/vacuum.c
src/backend/libpq/hba.c
src/backend/utils/init/flatfiles.c
src/backend/utils/init/postinit.c
src/backend/utils/misc/Makefile
src/backend/utils/misc/database.c [deleted file]
src/bin/initdb/initdb.c
src/include/catalog/catversion.h
src/include/catalog/pg_proc.h
src/include/libpq/hba.h
src/include/miscadmin.h

index 0962e32..474701f 100644 (file)
@@ -3,13 +3,19 @@
  * dbcommands.c
  *             Database management commands (create/drop database).
  *
+ * Note: database creation/destruction commands take ExclusiveLock on
+ * pg_database to ensure that no two proceed in parallel.  We must use
+ * at least this level of locking to ensure that no two backends try to
+ * write the flat-file copy of pg_database at once.  We avoid using
+ * AccessExclusiveLock since there's no need to lock out ordinary readers
+ * of pg_database.
  *
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.150 2005/02/20 02:21:34 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.151 2005/02/26 18:43:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -446,13 +452,13 @@ createdb(const CreatedbStmt *stmt)
        /*
         * Now OK to grab exclusive lock on pg_database.
         */
-       pg_database_rel = heap_openr(DatabaseRelationName, AccessExclusiveLock);
+       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))
        {
                /* Don't hold lock while doing recursive remove */
-               heap_close(pg_database_rel, AccessExclusiveLock);
+               heap_close(pg_database_rel, ExclusiveLock);
                remove_dbtablespaces(dboid);
                ereport(ERROR,
                                (errcode(ERRCODE_DUPLICATE_DATABASE),
@@ -498,13 +504,6 @@ createdb(const CreatedbStmt *stmt)
        /* Update indexes */
        CatalogUpdateIndexes(pg_database_rel, tuple);
 
-       /*
-        * Force dirty buffers out to disk, so that newly-connecting backends
-        * will see the new database in pg_database right away.  (They'll see
-        * an uncommitted tuple, but they don't care; see GetRawDatabaseInfo.)
-        */
-       FlushRelationBuffers(pg_database_rel, MaxBlockNumber);
-
        /* Close pg_database, but keep exclusive lock till commit */
        heap_close(pg_database_rel, NoLock);
 
@@ -542,12 +541,15 @@ dropdb(const char *dbname)
         * Obtain exclusive lock on pg_database.  We need this to ensure that
         * no new backend starts up in the target database while we are
         * deleting it.  (Actually, a new backend might still manage to start
-        * up, because it will read pg_database without any locking to
-        * discover the database's OID.  But it will detect its error in
-        * ReverifyMyDatabase and shut down before any serious damage is done.
-        * See postinit.c.)
+        * up, because it isn't able to lock pg_database while starting.  But
+        * it will detect its error in ReverifyMyDatabase and shut down before
+        * any serious damage is done.  See postinit.c.)
+        *
+        * An ExclusiveLock, rather than AccessExclusiveLock, is sufficient
+        * since ReverifyMyDatabase takes RowShareLock.  This allows ordinary
+        * readers of pg_database to proceed in parallel.
         */
-       pgdbrel = heap_openr(DatabaseRelationName, AccessExclusiveLock);
+       pgdbrel = heap_openr(DatabaseRelationName, ExclusiveLock);
 
        if (!get_db_info(dbname, &db_id, &db_owner, NULL,
                                         &db_istemplate, NULL, NULL, NULL, NULL))
@@ -638,14 +640,6 @@ dropdb(const char *dbname)
         */
        remove_dbtablespaces(db_id);
 
-       /*
-        * Force dirty buffers out to disk, so that newly-connecting backends
-        * will see the database tuple marked dead in pg_database right away.
-        * (They'll see an uncommitted deletion, but they don't care; see
-        * GetRawDatabaseInfo.)
-        */
-       FlushRelationBuffers(pgdbrel, MaxBlockNumber);
-
        /* Close pg_database, but keep exclusive lock till commit */
        heap_close(pgdbrel, NoLock);
 
@@ -671,10 +665,10 @@ RenameDatabase(const char *oldname, const char *newname)
                                key2;
 
        /*
-        * Obtain AccessExclusiveLock so that no new session gets started
+        * Obtain ExclusiveLock so that no new session gets started
         * while the rename is in progress.
         */
-       rel = heap_openr(DatabaseRelationName, AccessExclusiveLock);
+       rel = heap_openr(DatabaseRelationName, ExclusiveLock);
 
        ScanKeyInit(&key,
                                Anum_pg_database_datname,
@@ -742,14 +736,6 @@ RenameDatabase(const char *oldname, const char *newname)
 
        systable_endscan(scan);
 
-       /*
-        * Force dirty buffers out to disk, so that newly-connecting backends
-        * will see the renamed database in pg_database right away.  (They'll
-        * see an uncommitted tuple, but they don't care; see
-        * GetRawDatabaseInfo.)
-        */
-       FlushRelationBuffers(rel, MaxBlockNumber);
-
        /* Close pg_database, but keep exclusive lock till commit */
        heap_close(rel, NoLock);
 
@@ -779,9 +765,10 @@ AlterDatabaseSet(AlterDatabaseSetStmt *stmt)
        valuestr = flatten_set_variable_args(stmt->variable, stmt->value);
 
        /*
-        * We need AccessExclusiveLock so we can safely do FlushRelationBuffers.
+        * We don't need ExclusiveLock since we aren't updating the
+        * flat file.
         */
-       rel = heap_openr(DatabaseRelationName, AccessExclusiveLock);
+       rel = heap_openr(DatabaseRelationName, RowExclusiveLock);
        ScanKeyInit(&scankey,
                                Anum_pg_database_datname,
                                BTEqualStrategyNumber, F_NAMEEQ,
@@ -840,15 +827,7 @@ AlterDatabaseSet(AlterDatabaseSetStmt *stmt)
 
        systable_endscan(scan);
 
-       /*
-        * Force dirty buffers out to disk, so that newly-connecting backends
-        * will see the altered row in pg_database right away.  (They'll
-        * see an uncommitted tuple, but they don't care; see
-        * GetRawDatabaseInfo.)
-        */
-       FlushRelationBuffers(rel, MaxBlockNumber);
-
-       /* Close pg_database, but keep exclusive lock till commit */
+       /* Close pg_database, but keep lock till commit */
        heap_close(rel, NoLock);
 
        /*
@@ -871,9 +850,10 @@ AlterDatabaseOwner(const char *dbname, AclId newOwnerSysId)
        Form_pg_database datForm;
 
        /*
-        * We need AccessExclusiveLock so we can safely do FlushRelationBuffers.
+        * We don't need ExclusiveLock since we aren't updating the
+        * flat file.
         */
-       rel = heap_openr(DatabaseRelationName, AccessExclusiveLock);
+       rel = heap_openr(DatabaseRelationName, RowExclusiveLock);
        ScanKeyInit(&scankey,
                                Anum_pg_database_datname,
                                BTEqualStrategyNumber, F_NAMEEQ,
@@ -937,22 +917,11 @@ AlterDatabaseOwner(const char *dbname, AclId newOwnerSysId)
                CatalogUpdateIndexes(rel, newtuple);
 
                heap_freetuple(newtuple);
-
-               /* must release buffer pins before FlushRelationBuffers */
-               systable_endscan(scan);
-
-               /*
-                * Force dirty buffers out to disk, so that newly-connecting backends
-                * will see the altered row in pg_database right away.  (They'll
-                * see an uncommitted tuple, but they don't care; see
-                * GetRawDatabaseInfo.)
-                */
-               FlushRelationBuffers(rel, MaxBlockNumber);
        }
-       else
-               systable_endscan(scan);
 
-       /* Close pg_database, but keep exclusive lock till commit */
+       systable_endscan(scan);
+
+       /* Close pg_database, but keep lock till commit */
        heap_close(rel, NoLock);
 
        /*
index c818d8f..f4fbbae 100644 (file)
@@ -13,7 +13,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.301 2005/02/20 02:21:34 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.302 2005/02/26 18:43:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -704,11 +704,12 @@ vac_update_relstats(Oid relid, BlockNumber num_pages, double num_tuples,
  *             We violate no-overwrite semantics here by storing new values for the
  *             statistics columns directly into the tuple that's already on the page.
  *             As with vac_update_relstats, this avoids leaving dead tuples behind
- *             after a VACUUM; which is good since GetRawDatabaseInfo
- *             can get confused by finding dead tuples in pg_database.
+ *             after a VACUUM.
  *
  *             This routine is shared by full and lazy VACUUM.  Note that it is only
  *             applied after a database-wide VACUUM operation.
+ *
+ *             Note that we don't bother to update the flat-file copy of pg_database.
  */
 static void
 vac_update_dbstats(Oid dbid,
index 9a65ee1..658b42b 100644 (file)
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/libpq/hba.c,v 1.139 2005/02/20 04:45:57 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/libpq/hba.c,v 1.140 2005/02/26 18:43:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
+#include <ctype.h>
 #include <pwd.h>
 #include <fcntl.h>
 #include <sys/param.h>
@@ -37,6 +38,8 @@
 #include "utils/guc.h"
 
 
+#define atooid(x)  ((Oid) strtoul((x), NULL, 10))
+
 /* Max size of username ident server can return */
 #define IDENT_USERNAME_MAX 512
 
@@ -1059,6 +1062,51 @@ load_hba(void)
        FreeFile(file);
 }
 
+/*
+ * Read and parse one line from the flat pg_database file.
+ *
+ * Returns TRUE on success, FALSE if EOF; bad data causes elog(FATAL).
+ *
+ * Output parameters:
+ *     dbname: gets database name (must be of size NAMEDATALEN bytes)
+ *     dboid: gets database OID
+ *     dbtablespace: gets database's default tablespace's OID
+ *
+ * This is not much related to the other functions in hba.c, but we put it
+ * here because it uses the next_token() infrastructure.
+ */
+bool
+read_pg_database_line(FILE *fp, char *dbname,
+                                         Oid *dboid, Oid *dbtablespace)
+{
+       char            buf[MAX_TOKEN];
+
+       if (feof(fp))
+               return false;
+       next_token(fp, buf, sizeof(buf));
+       if (!buf[0])
+               return false;
+       if (strlen(buf) >= NAMEDATALEN)
+               elog(FATAL, "bad data in flat pg_database file");
+       strcpy(dbname, buf);
+       next_token(fp, buf, sizeof(buf));
+       if (!isdigit((unsigned char) buf[0]))
+               elog(FATAL, "bad data in flat pg_database file");
+       *dboid = atooid(buf);
+       next_token(fp, buf, sizeof(buf));
+       if (!isdigit((unsigned char) buf[0]))
+               elog(FATAL, "bad data in flat pg_database file");
+       *dbtablespace = atooid(buf);
+       /* discard datfrozenxid */
+       next_token(fp, buf, sizeof(buf));
+       if (!isdigit((unsigned char) buf[0]))
+               elog(FATAL, "bad data in flat pg_database file");
+       /* expect EOL next */
+       next_token(fp, buf, sizeof(buf));
+       if (buf[0])
+               elog(FATAL, "bad data in flat pg_database file");
+       return true;
+}
 
 /*
  *     Process one line from the ident config file.
index 8968d57..e7ddd0a 100644 (file)
@@ -22,7 +22,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/backend/utils/init/flatfiles.c,v 1.3 2005/02/20 22:02:19 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/init/flatfiles.c,v 1.4 2005/02/26 18:43:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -243,10 +243,12 @@ write_database_file(Relation drel)
                Form_pg_database dbform = (Form_pg_database) GETSTRUCT(tuple);
                char       *datname;
                Oid                     datoid;
+               Oid                     dattablespace;
                TransactionId datfrozenxid;
 
                datname = NameStr(dbform->datname);
                datoid = HeapTupleGetOid(tuple);
+               dattablespace = dbform->dattablespace;
                datfrozenxid = dbform->datfrozenxid;
 
                /*
@@ -276,13 +278,13 @@ write_database_file(Relation drel)
                }
 
                /*
-                * The file format is: "dbname" oid frozenxid
+                * The file format is: "dbname" oid tablespace frozenxid
                 *
                 * The xid is not needed for backend startup, but may be of use
                 * for forensic purposes.
                 */
                fputs_quote(datname, fp);
-               fprintf(fp, " %u %u\n", datoid, datfrozenxid);
+               fprintf(fp, " %u %u %u\n", datoid, dattablespace, datfrozenxid);
        }
        heap_endscan(scan);
 
@@ -830,15 +832,3 @@ flatfile_update_trigger(PG_FUNCTION_ARGS)
 
        return PointerGetDatum(NULL);
 }
-
-
-/*
- * Old version of trigger --- remove after we can force an initdb
- */
-extern Datum update_pg_pwd_and_pg_group(PG_FUNCTION_ARGS);
-
-Datum
-update_pg_pwd_and_pg_group(PG_FUNCTION_ARGS)
-{
-       return flatfile_update_trigger(fcinfo);
-}
index 53eb47a..d1479bb 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.140 2005/02/20 21:46:49 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.141 2005/02/26 18:43:33 tgl Exp $
  *
  *
  *-------------------------------------------------------------------------
 #include "catalog/pg_database.h"
 #include "catalog/pg_shadow.h"
 #include "catalog/pg_tablespace.h"
+#include "libpq/hba.h"
 #include "mb/pg_wchar.h"
 #include "miscadmin.h"
 #include "postmaster/postmaster.h"
-#include "storage/backendid.h"
+#include "storage/fd.h"
 #include "storage/ipc.h"
 #include "storage/proc.h"
 #include "storage/sinval.h"
 #include "storage/smgr.h"
+#include "utils/flatfiles.h"
 #include "utils/fmgroids.h"
 #include "utils/guc.h"
 #include "utils/portal.h"
@@ -42,6 +44,7 @@
 #include "utils/syscache.h"
 
 
+static bool FindMyDatabase(const char *name, Oid *db_id, Oid *db_tablespace);
 static void ReverifyMyDatabase(const char *name);
 static void InitCommunication(void);
 static void ShutdownPostgres(int code, Datum arg);
@@ -51,18 +54,60 @@ static bool ThereIsAtLeastOneUser(void);
 /*** InitPostgres support ***/
 
 
-/* --------------------------------
- *             ReverifyMyDatabase
+/*
+ * FindMyDatabase -- get the critical info needed to locate my database
  *
- * Since we are forced to fetch the database OID out of pg_database without
- * benefit of locking or transaction ID checking (see utils/misc/database.c),
- * we might have gotten a wrong answer.  Or, we might have attached to a
- * database that's in process of being destroyed by destroydb().  This
- * routine is called after we have all the locking and other infrastructure
- * running --- now we can check that we are really attached to a valid
- * database.
+ * Find the named database in pg_database, return its database OID and the
+ * OID of its default tablespace.  Return TRUE if found, FALSE if not.
  *
- * In reality, if destroydb() is running in parallel with our startup,
+ * Since we are not yet up and running as a backend, we cannot look directly
+ * at pg_database (we can't obtain locks nor participate in transactions).
+ * So to get the info we need before starting up, we must look at the "flat
+ * file" copy of pg_database that is helpfully maintained by flatfiles.c.
+ * This is subject to various race conditions, so after we have the
+ * transaction infrastructure started, we have to recheck the information;
+ * see ReverifyMyDatabase.
+ */
+static bool
+FindMyDatabase(const char *name, Oid *db_id, Oid *db_tablespace)
+{
+       bool            result = false;
+       char       *filename;
+       FILE       *db_file;
+       char            thisname[NAMEDATALEN];
+
+       filename = database_getflatfilename();
+       db_file = AllocateFile(filename, "r");
+       if (db_file == NULL)
+               ereport(FATAL,
+                               (errcode_for_file_access(),
+                                errmsg("could not open file \"%s\": %m", filename)));
+
+       while (read_pg_database_line(db_file, thisname, db_id, db_tablespace))
+       {
+               if (strcmp(thisname, name) == 0)
+               {
+                       result = true;
+                       break;
+               }
+       }
+
+       FreeFile(db_file);
+       pfree(filename);
+
+       return result;
+}
+
+/*
+ * ReverifyMyDatabase -- recheck info obtained by FindMyDatabase
+ *
+ * Since FindMyDatabase cannot lock pg_database, the information it read
+ * could be stale; for example we might have attached to a database that's in
+ * process of being destroyed by dropdb().  This routine is called after
+ * we have all the locking and other infrastructure running --- now we can
+ * check that we are really attached to a valid database.
+ *
+ * In reality, if dropdb() is running in parallel with our startup,
  * it's pretty likely that we will have failed before now, due to being
  * unable to read some of the system tables within the doomed database.
  * This routine just exists to make *sure* we have not started up in an
@@ -75,7 +120,6 @@ static bool ThereIsAtLeastOneUser(void);
  * To avoid having to read pg_database more times than necessary
  * during session startup, this place is also fitting to set up any
  * database-specific configuration variables.
- * --------------------------------
  */
 static void
 ReverifyMyDatabase(const char *name)
@@ -87,10 +131,10 @@ ReverifyMyDatabase(const char *name)
        Form_pg_database dbform;
 
        /*
-        * Because we grab AccessShareLock here, we can be sure that destroydb
+        * Because we grab RowShareLock here, we can be sure that dropdb()
         * is not running in parallel with us (any more).
         */
-       pgdbrel = heap_openr(DatabaseRelationName, AccessShareLock);
+       pgdbrel = heap_openr(DatabaseRelationName, RowShareLock);
 
        ScanKeyInit(&key,
                                Anum_pg_database_datname,
@@ -104,7 +148,7 @@ ReverifyMyDatabase(const char *name)
                HeapTupleGetOid(tup) != MyDatabaseId)
        {
                /* OOPS */
-               heap_close(pgdbrel, AccessShareLock);
+               heap_close(pgdbrel, RowShareLock);
 
                /*
                 * The only real problem I could have created is to load dirty
@@ -131,7 +175,7 @@ ReverifyMyDatabase(const char *name)
                                name)));
 
        /*
-        * OK, we're golden.  Only other to-do item is to save the encoding
+        * OK, we're golden.  Next to-do item is to save the encoding
         * info out of the pg_database tuple.
         */
        SetDatabaseEncoding(dbform->encoding);
@@ -143,7 +187,7 @@ ReverifyMyDatabase(const char *name)
                                        PGC_BACKEND, PGC_S_DEFAULT);
 
        /*
-        * Set up database-specific configuration variables.
+        * Lastly, set up any database-specific configuration variables.
         */
        if (IsUnderPostmaster)
        {
@@ -161,7 +205,7 @@ ReverifyMyDatabase(const char *name)
        }
 
        heap_endscan(pgdbscan);
-       heap_close(pgdbrel, AccessShareLock);
+       heap_close(pgdbrel, RowShareLock);
 }
 
 
@@ -261,11 +305,9 @@ InitPostgres(const char *dbname, const char *username)
                /*
                 * Find oid and tablespace of the database we're about to open.
                 * Since we're not yet up and running we have to use the hackish
-                * GetRawDatabaseInfo.
+                * FindMyDatabase.
                 */
-               GetRawDatabaseInfo(dbname, &MyDatabaseId, &MyDatabaseTableSpace);
-
-               if (!OidIsValid(MyDatabaseId))
+               if (!FindMyDatabase(dbname, &MyDatabaseId, &MyDatabaseTableSpace))
                        ereport(FATAL,
                                        (errcode(ERRCODE_UNDEFINED_DATABASE),
                                         errmsg("database \"%s\" does not exist",
index f907f22..afa3216 100644 (file)
@@ -1,4 +1,12 @@
-# $PostgreSQL: pgsql/src/backend/utils/misc/Makefile,v 1.22 2003/11/29 19:52:03 pgsql Exp $
+#-------------------------------------------------------------------------
+#
+# Makefile--
+#    Makefile for utils/misc
+#
+# IDENTIFICATION
+#    $PostgreSQL: pgsql/src/backend/utils/misc/Makefile,v 1.23 2005/02/26 18:43:33 tgl Exp $
+#
+#-------------------------------------------------------------------------
 
 subdir = src/backend/utils/misc
 top_builddir = ../../../..
@@ -6,10 +14,10 @@ include $(top_builddir)/src/Makefile.global
 
 override CPPFLAGS := -I$(srcdir) $(CPPFLAGS)
 
-OBJS = database.o superuser.o guc.o help_config.o ps_status.o
+OBJS = guc.o help_config.o ps_status.o superuser.o
 
 # This location might depend on the installation directories. Therefore
-# we can't subsitute it into config.h.
+# we can't subsitute it into pg_config.h.
 ifdef krb_srvtab
 override CPPFLAGS += -DPG_KRB_SRVTAB='"$(krb_srvtab)"'
 endif
diff --git a/src/backend/utils/misc/database.c b/src/backend/utils/misc/database.c
deleted file mode 100644 (file)
index 66ea6db..0000000
+++ /dev/null
@@ -1,189 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * database.c
- *       miscellaneous initialization support stuff
- *
- * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- *
- * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/misc/database.c,v 1.63 2004/12/31 22:02:45 pgsql Exp $
- *
- *-------------------------------------------------------------------------
- */
-#include "postgres.h"
-
-#include <fcntl.h>
-#include <unistd.h>
-
-#include "access/xact.h"
-#include "catalog/catname.h"
-#include "catalog/catalog.h"
-#include "catalog/pg_database.h"
-#include "catalog/pg_tablespace.h"
-#include "miscadmin.h"
-#include "utils/syscache.h"
-
-
-static bool PhonyHeapTupleSatisfiesNow(HeapTupleHeader tuple);
-
-
-/* --------------------------------
- *     GetRawDatabaseInfo() -- Find the OID and tablespace of the database.
- *
- *             We need both the OID and the default tablespace in order to find
- *             the database's system catalogs.  Moreover the database's OID forms
- *             half of the unique key for the system caches and lock tables, so
- *             we must have it before we can use any of the cache mechanisms.
- *             To get around these problems, this code opens and scans the
- *             pg_database relation by hand.
- *
- *             This code knows way more than it should about the layout of
- *             tuples on disk, but there seems to be no help for that.
- *             We're pulling ourselves up by the bootstraps here...
- * --------------------------------
- */
-void
-GetRawDatabaseInfo(const char *name, Oid *db_id, Oid *db_tablespace)
-{
-       int                     dbfd;
-       int                     nbytes;
-       HeapTupleData tup;
-       Form_pg_database tup_db;
-       Page            pg;
-       char       *dbfname;
-       RelFileNode rnode;
-
-       /* hard-wired path to pg_database */
-       rnode.spcNode = GLOBALTABLESPACE_OID;
-       rnode.dbNode = 0;
-       rnode.relNode = RelOid_pg_database;
-
-       dbfname = relpath(rnode);
-
-       if ((dbfd = open(dbfname, O_RDONLY | PG_BINARY, 0)) < 0)
-               ereport(FATAL,
-                               (errcode_for_file_access(),
-                                errmsg("could not open file \"%s\": %m", dbfname)));
-
-       pfree(dbfname);
-
-       /*
-        * read and examine every page in pg_database
-        *
-        * Raw I/O! Read those tuples the hard way! Yow!
-        *
-        * Why don't we use the access methods or move this code someplace else?
-        * This is really pg_database schema dependent code.  Perhaps it
-        * should go in lib/catalog/pg_database? -cim 10/3/90
-        *
-        * mao replies 4 apr 91:  yeah, maybe this should be moved to
-        * lib/catalog.  however, we CANNOT use the access methods since those
-        * use the buffer cache, which uses the relation cache, which requires
-        * that the dbid be set, which is what we're trying to do here.
-        *
-        */
-       pg = (Page) palloc(BLCKSZ);
-
-       while ((nbytes = read(dbfd, pg, BLCKSZ)) == BLCKSZ)
-       {
-               OffsetNumber max = PageGetMaxOffsetNumber(pg);
-               OffsetNumber lineoff;
-
-               /* look at each tuple on the page */
-               for (lineoff = FirstOffsetNumber; lineoff <= max; lineoff++)
-               {
-                       ItemId          lpp = PageGetItemId(pg, lineoff);
-
-                       /* if it's a freed tuple, ignore it */
-                       if (!ItemIdIsUsed(lpp))
-                               continue;
-
-                       /* get a pointer to the tuple itself */
-                       tup.t_datamcxt = NULL;
-                       tup.t_data = (HeapTupleHeader) PageGetItem(pg, lpp);
-
-                       /*
-                        * Check to see if tuple is valid (committed).
-                        *
-                        * XXX warning, will robinson: violation of transaction semantics
-                        * happens right here.  We cannot really determine if the
-                        * tuple is valid without checking transaction commit status,
-                        * and the only way to do that at init time is to paw over
-                        * pg_clog by hand, too.  Instead of checking, we assume that
-                        * the inserting transaction committed, and that any deleting
-                        * transaction did also, unless shown otherwise by on-row
-                        * commit status bits.
-                        *
-                        * All in all, this code is pretty shaky.  We will cross-check
-                        * our result in ReverifyMyDatabase() in postinit.c.
-                        *
-                        * NOTE: if a bogus tuple in pg_database prevents connection to a
-                        * valid database, a fix is to connect to another database and
-                        * do "select * from pg_database".      That should cause
-                        * committed and dead tuples to be marked with correct states.
-                        *
-                        * XXX wouldn't it be better to let new backends read the
-                        * database info from a flat file, handled the same way we
-                        * handle the password relation?
-                        */
-                       if (!PhonyHeapTupleSatisfiesNow(tup.t_data))
-                               continue;
-
-                       /*
-                        * Okay, see if this is the one we want.
-                        */
-                       tup_db = (Form_pg_database) GETSTRUCT(&tup);
-
-                       if (strcmp(name, NameStr(tup_db->datname)) == 0)
-                       {
-                               /* Found it; extract the db's OID and tablespace. */
-                               *db_id = HeapTupleGetOid(&tup);
-                               *db_tablespace = tup_db->dattablespace;
-                               goto done;
-                       }
-               }
-       }
-
-       /* failed to find it... */
-       *db_id = InvalidOid;
-       *db_tablespace = InvalidOid;
-
-done:
-       close(dbfd);
-       pfree(pg);
-}
-
-/*
- * PhonyHeapTupleSatisfiesNow --- cut-down tuple time qual test
- *
- * This is a simplified version of HeapTupleSatisfiesNow() that does not
- * depend on having transaction commit info available. Any transaction
- * that touched the tuple is assumed committed unless later marked invalid.
- * (While we could think about more complex rules, this seems appropriate
- * for examining pg_database, since both CREATE DATABASE and DROP DATABASE
- * are non-roll-back-able.)
- */
-static bool
-PhonyHeapTupleSatisfiesNow(HeapTupleHeader tuple)
-{
-       if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
-       {
-               if (tuple->t_infomask & HEAP_XMIN_INVALID)
-                       return false;
-
-               if (tuple->t_infomask & HEAP_MOVED_OFF)
-                       return false;
-               /* else assume committed */
-       }
-
-       if (tuple->t_infomask & HEAP_XMAX_INVALID)      /* xid invalid or aborted */
-               return true;
-
-       /* assume xmax transaction committed */
-       if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
-               return true;
-
-       return false;
-}
index 5d8338f..e6cfc05 100644 (file)
@@ -39,7 +39,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  * Portions taken from FreeBSD.
  *
- * $PostgreSQL: pgsql/src/bin/initdb/initdb.c,v 1.75 2005/02/22 04:38:22 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/initdb/initdb.c,v 1.76 2005/02/26 18:43:34 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1319,15 +1319,18 @@ setup_shadow(void)
        char      **line;
        static char *pg_shadow_setup[] = {
                /*
-                * Create a trigger so that direct updates to pg_shadow will be
-                * written to the flat password/group files pg_pwd and pg_group
+                * Create triggers to ensure manual updates to shared catalogs
+                * will be reflected into their "flat file" copies.
                 */
-               "CREATE TRIGGER pg_sync_pg_pwd "
-               "  AFTER INSERT OR UPDATE OR DELETE ON pg_shadow "
-               "  FOR EACH ROW EXECUTE PROCEDURE update_pg_pwd_and_pg_group();\n",
+               "CREATE TRIGGER pg_sync_pg_database "
+               "  AFTER INSERT OR UPDATE OR DELETE ON pg_database "
+               "  FOR EACH STATEMENT EXECUTE PROCEDURE flatfile_update_trigger();\n",
                "CREATE TRIGGER pg_sync_pg_group "
                "  AFTER INSERT OR UPDATE OR DELETE ON pg_group "
-               "  FOR EACH ROW EXECUTE PROCEDURE update_pg_pwd_and_pg_group();\n",
+               "  FOR EACH STATEMENT EXECUTE PROCEDURE flatfile_update_trigger();\n",
+               "CREATE TRIGGER pg_sync_pg_pwd "
+               "  AFTER INSERT OR UPDATE OR DELETE ON pg_shadow "
+               "  FOR EACH STATEMENT EXECUTE PROCEDURE flatfile_update_trigger();\n",
 
                /*
                 * needs to be done before alter user, because alter user checks
index e4f6a74..ca44b24 100644 (file)
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.254 2005/02/25 16:13:29 teodor Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.255 2005/02/26 18:43:34 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     200502251
+#define CATALOG_VERSION_NO     200502261
 
 #endif
index 16867cb..e456e96 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.349 2004/12/31 22:03:25 pgsql Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.350 2005/02/26 18:43:34 tgl Exp $
  *
  * NOTES
  *       The script catalog/genbki.sh reads this file and generates .bki
@@ -2133,8 +2133,8 @@ DESCR("matches LIKE expression, case-insensitive");
 DATA(insert OID = 1661 (  bpcharicnlike                PGNSP PGUID 12 f f t f i 2 16 "1042 25" _null_ texticnlike - _null_ ));
 DESCR("does not match LIKE expression, case-insensitive");
 
-DATA(insert OID = 1689 (  update_pg_pwd_and_pg_group  PGNSP PGUID 12 f f t f v 0 2279  "" _null_       update_pg_pwd_and_pg_group - _null_ ));
-DESCR("update pg_pwd and pg_group files");
+DATA(insert OID = 1689 (  flatfile_update_trigger  PGNSP PGUID 12 f f t f v 0 2279  "" _null_  flatfile_update_trigger - _null_ ));
+DESCR("update flat-file copy of a shared catalog");
 
 /* Oracle Compatibility Related Functions - By Edmund Mergl <E.Mergl@bawue.de> */
 DATA(insert OID =  868 (  strpos          PGNSP PGUID 12 f f t f i 2 23 "25 25" _null_ textpos - _null_ ));
index a284edf..0656e6a 100644 (file)
@@ -4,19 +4,16 @@
  *       Interface to hba.c
  *
  *
- * $PostgreSQL: pgsql/src/include/libpq/hba.h,v 1.35 2004/02/02 16:58:30 neilc Exp $
+ * $PostgreSQL: pgsql/src/include/libpq/hba.h,v 1.36 2005/02/26 18:43:34 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #ifndef HBA_H
 #define HBA_H
 
-#ifndef WIN32
-#include <netinet/in.h>
-#endif
-
 #include "nodes/pg_list.h"
 
+
 typedef enum UserAuth
 {
        uaReject,
@@ -41,5 +38,7 @@ extern void load_user(void);
 extern void load_group(void);
 extern int     hba_getauthmethod(hbaPort *port);
 extern int     authident(hbaPort *port);
+extern bool    read_pg_database_line(FILE *fp, char *dbname,
+                                                                 Oid *dboid, Oid *dbtablespace);
 
-#endif
+#endif /* HBA_H */
index e533397..3e9b7d9 100644 (file)
@@ -13,7 +13,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/miscadmin.h,v 1.174 2004/12/31 22:03:19 pgsql Exp $
+ * $PostgreSQL: pgsql/src/include/miscadmin.h,v 1.175 2005/02/26 18:43:34 tgl Exp $
  *
  * NOTES
  *       some of the information in this file should be moved to other files.
@@ -225,9 +225,6 @@ extern void check_stack_depth(void);
 
 extern char *DatabasePath;
 
-/* in utils/misc/database.c */
-extern void GetRawDatabaseInfo(const char *name, Oid *db_id, Oid *db_tablespace);
-
 /* now in utils/init/miscinit.c */
 extern void SetDatabasePath(const char *path);