Commit 60b2444c authored by Tom Lane's avatar Tom Lane

Add code to prevent transaction ID wraparound by enforcing a safe limit

in GetNewTransactionId().  Since the limit value has to be computed
before we run any real transactions, this requires adding code to database
startup to scan pg_database and determine the oldest datfrozenxid.
This can conveniently be combined with the first stage of an attack on
the problem that the 'flat file' copies of pg_shadow and pg_group are
not properly updated during WAL recovery.  The code I've added to
startup resides in a new file src/backend/utils/init/flatfiles.c, and
it is responsible for rewriting the flat files as well as initializing
the XID wraparound limit value.  This will eventually allow us to get
rid of GetRawDatabaseInfo too, but we'll need an initdb so we can add
a trigger to pg_database.
parent 617d16f4
<!--
$PostgreSQL: pgsql/doc/src/sgml/maintenance.sgml,v 1.40 2004/12/27 22:30:10 tgl Exp $
$PostgreSQL: pgsql/doc/src/sgml/maintenance.sgml,v 1.41 2005/02/20 02:21:26 tgl Exp $
-->
<chapter id="maintenance">
......@@ -290,7 +290,7 @@ $PostgreSQL: pgsql/doc/src/sgml/maintenance.sgml,v 1.40 2004/12/27 22:30:10 tgl
transaction's XID is <quote>in the future</> and should not be visible
to the current transaction. But since transaction IDs have limited size
(32 bits at this writing) a cluster that runs for a long time (more
than 4 billion transactions) will suffer <firstterm>transaction ID
than 4 billion transactions) would suffer <firstterm>transaction ID
wraparound</>: the XID counter wraps around to zero, and all of a sudden
transactions that were in the past appear to be in the future &mdash; which
means their outputs become invisible. In short, catastrophic data loss.
......@@ -313,8 +313,13 @@ $PostgreSQL: pgsql/doc/src/sgml/maintenance.sgml,v 1.40 2004/12/27 22:30:10 tgl
In practice this isn't an onerous requirement, but since the
consequences of failing to meet it can be complete data loss (not
just wasted disk space or slow performance), some special provisions
have been made to help database administrators keep track of the
time since the last <command>VACUUM</>. The remainder of this
have been made to help database administrators avoid disaster.
For each database in the cluster, <productname>PostgreSQL</productname>
keeps track of the time of the last database-wide <command>VACUUM</>.
When any database approaches the billion-transaction danger level,
the system begins to emit warning messages. If nothing is done, it
will eventually shut down normal operations until appropriate
manual maintenance is done. The remainder of this
section gives the details.
</para>
......@@ -363,7 +368,8 @@ $PostgreSQL: pgsql/doc/src/sgml/maintenance.sgml,v 1.40 2004/12/27 22:30:10 tgl
statistics in the system table <literal>pg_database</>. In particular,
the <literal>datfrozenxid</> column of a database's
<literal>pg_database</> row is updated at the completion of any
database-wide <command>VACUUM</command> operation (i.e., <command>VACUUM</> that does not
database-wide <command>VACUUM</command> operation (i.e.,
<command>VACUUM</> that does not
name a specific table). The value stored in this field is the freeze
cutoff XID that was used by that <command>VACUUM</> command. All normal
XIDs older than this cutoff XID are guaranteed to have been replaced by
......@@ -391,12 +397,37 @@ SELECT datname, age(datfrozenxid) FROM pg_database;
<programlisting>
play=# VACUUM;
WARNING: some databases have not been vacuumed in 1613770184 transactions
HINT: Better vacuum them within 533713463 transactions, or you may have a wraparound failure.
WARNING: database "mydb" must be vacuumed within 177009986 transactions
HINT: To avoid a database shutdown, execute a full-database VACUUM in "mydb".
VACUUM
</programlisting>
</para>
<para>
If the warnings emitted by <command>VACUUM</> go ignored, then
<productname>PostgreSQL</productname> will begin to emit a warning
like the above on every transaction start once there are fewer than 10
million transactions left until wraparound. If those warnings also are
ignored, the system will shut down and refuse to execute any new
transactions once there are fewer than 1 million transactions left
until wraparound:
<programlisting>
play=# select 2+2;
ERROR: database is shut down to avoid wraparound data loss in database "mydb"
HINT: Stop the postmaster and use a standalone backend to VACUUM in "mydb".
</programlisting>
The 1-million-transaction safety margin exists to let the
administrator recover without data loss, by manually executing the
required <command>VACUUM</> commands. However, since the system will not
execute commands once it has gone into the safety shutdown mode,
the only way to do this is to stop the postmaster and use a standalone
backend to execute <command>VACUUM</>. The shutdown mode is not enforced
by a standalone backend. See the <xref linkend="app-postgres"> reference
page for details about using a standalone backend.
</para>
<para>
<command>VACUUM</> with the <command>FREEZE</> option uses a more
aggressive freezing policy: row versions are frozen if they are old enough
......@@ -410,26 +441,19 @@ VACUUM
It should also be used to prepare any user-created databases that
are to be marked <literal>datallowconn</> = <literal>false</> in
<literal>pg_database</>, since there isn't any convenient way to
<command>VACUUM</command> a database that you can't connect to. Note that
<command>VACUUM</command>'s automatic warning message about
unvacuumed databases will ignore <literal>pg_database</> entries
with <literal>datallowconn</> = <literal>false</>, so as to avoid
giving false warnings about these databases; therefore it's up to
you to ensure that such databases are frozen correctly.
<command>VACUUM</command> a database that you can't connect to.
</para>
<warning>
<para>
To be sure of safety against transaction wraparound, it is necessary
to vacuum <emphasis>every</> table, including system catalogs, in
<emphasis>every</> database at least once every billion transactions.
We have seen data loss situations caused by people deciding that they
only needed to vacuum their active user tables, rather than issuing
database-wide vacuum commands. That will appear to work fine ...
for a while.
A database that is marked <literal>datallowconn</> = <literal>false</>
in <literal>pg_database</> is assumed to be properly frozen; the
automatic warnings and wraparound protection shutdown do not take
such databases into account. Therefore it's up to you to ensure
you've correctly frozen a database before you mark it with
<literal>datallowconn</> = <literal>false</>.
</para>
</warning>
</sect2>
</sect1>
......
......@@ -6,7 +6,7 @@
* Copyright (c) 2000-2005, PostgreSQL Global Development Group
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/transam/varsup.c,v 1.60 2005/01/01 05:43:06 momjian Exp $
* $PostgreSQL: pgsql/src/backend/access/transam/varsup.c,v 1.61 2005/02/20 02:21:28 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -16,8 +16,10 @@
#include "access/clog.h"
#include "access/subtrans.h"
#include "access/transam.h"
#include "miscadmin.h"
#include "storage/ipc.h"
#include "storage/proc.h"
#include "utils/builtins.h"
/* Number of OIDs to prefetch (preallocate) per XLOG write */
......@@ -46,6 +48,37 @@ GetNewTransactionId(bool isSubXact)
xid = ShmemVariableCache->nextXid;
/*
* Check to see if it's safe to assign another XID. This protects
* against catastrophic data loss due to XID wraparound. The basic
* rules are: warn if we're past xidWarnLimit, and refuse to execute
* transactions if we're past xidStopLimit, unless we are running in
* a standalone backend (which gives an escape hatch to the DBA who
* ignored all those warnings).
*
* Test is coded to fall out as fast as possible during normal operation,
* ie, when the warn limit is set and we haven't violated it.
*/
if (TransactionIdFollowsOrEquals(xid, ShmemVariableCache->xidWarnLimit) &&
TransactionIdIsValid(ShmemVariableCache->xidWarnLimit))
{
if (IsUnderPostmaster &&
TransactionIdFollowsOrEquals(xid, ShmemVariableCache->xidStopLimit))
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("database is shut down to avoid wraparound data loss in database \"%s\"",
NameStr(ShmemVariableCache->limit_datname)),
errhint("Stop the postmaster and use a standalone backend to VACUUM in \"%s\".",
NameStr(ShmemVariableCache->limit_datname))));
else
ereport(WARNING,
(errmsg("database \"%s\" must be vacuumed within %u transactions",
NameStr(ShmemVariableCache->limit_datname),
ShmemVariableCache->xidWrapLimit - xid),
errhint("To avoid a database shutdown, execute a full-database VACUUM in \"%s\".",
NameStr(ShmemVariableCache->limit_datname))));
}
/*
* If we are allocating the first XID of a new page of the commit log,
* zero out that commit-log page before returning. We must do this
......@@ -137,6 +170,84 @@ ReadNewTransactionId(void)
return xid;
}
/*
* Determine the last safe XID to allocate given the currently oldest
* datfrozenxid (ie, the oldest XID that might exist in any database
* of our cluster).
*/
void
SetTransactionIdLimit(TransactionId oldest_datfrozenxid,
Name oldest_datname)
{
TransactionId xidWarnLimit;
TransactionId xidStopLimit;
TransactionId xidWrapLimit;
TransactionId curXid;
Assert(TransactionIdIsValid(oldest_datfrozenxid));
/*
* The place where we actually get into deep trouble is halfway around
* from the oldest potentially-existing XID. (This calculation is
* probably off by one or two counts, because the special XIDs reduce the
* size of the loop a little bit. But we throw in plenty of slop below,
* so it doesn't matter.)
*/
xidWrapLimit = oldest_datfrozenxid + (MaxTransactionId >> 1);
if (xidWrapLimit < FirstNormalTransactionId)
xidWrapLimit += FirstNormalTransactionId;
/*
* We'll refuse to continue assigning XIDs in interactive mode once
* we get within 1M transactions of data loss. This leaves lots
* of room for the DBA to fool around fixing things in a standalone
* backend, while not being significant compared to total XID space.
* (Note that since vacuuming requires one transaction per table
* cleaned, we had better be sure there's lots of XIDs left...)
*/
xidStopLimit = xidWrapLimit - 1000000;
if (xidStopLimit < FirstNormalTransactionId)
xidStopLimit -= FirstNormalTransactionId;
/*
* We'll start complaining loudly when we get within 10M transactions
* of the stop point. This is kind of arbitrary, but if you let your
* gas gauge get down to 1% of full, would you be looking for the
* next gas station? We need to be fairly liberal about this number
* because there are lots of scenarios where most transactions are
* done by automatic clients that won't pay attention to warnings.
* (No, we're not gonna make this configurable. If you know enough to
* configure it, you know enough to not get in this kind of trouble in
* the first place.)
*/
xidWarnLimit = xidStopLimit - 10000000;
if (xidWarnLimit < FirstNormalTransactionId)
xidWarnLimit -= FirstNormalTransactionId;
/* Grab lock for just long enough to set the new limit values */
LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
ShmemVariableCache->xidWarnLimit = xidWarnLimit;
ShmemVariableCache->xidStopLimit = xidStopLimit;
ShmemVariableCache->xidWrapLimit = xidWrapLimit;
namecpy(&ShmemVariableCache->limit_datname, oldest_datname);
curXid = ShmemVariableCache->nextXid;
LWLockRelease(XidGenLock);
/* Log the info */
ereport(LOG,
(errmsg("transaction ID wrap limit is %u, limited by database \"%s\"",
xidWrapLimit, NameStr(*oldest_datname))));
/* Give an immediate warning if past the wrap warn point */
if (TransactionIdFollowsOrEquals(curXid, xidWarnLimit))
ereport(WARNING,
(errmsg("database \"%s\" must be vacuumed within %u transactions",
NameStr(*oldest_datname),
xidWrapLimit - curXid),
errhint("To avoid a database shutdown, execute a full-database VACUUM in \"%s\".",
NameStr(*oldest_datname))));
}
/* ----------------------------------------------------------------
* object id generation support
* ----------------------------------------------------------------
......
......@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.195 2004/12/31 21:59:29 pgsql Exp $
* $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.196 2005/02/20 02:21:28 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -28,7 +28,6 @@
#include "commands/async.h"
#include "commands/tablecmds.h"
#include "commands/trigger.h"
#include "commands/user.h"
#include "executor/spi.h"
#include "libpq/be-fsstubs.h"
#include "miscadmin.h"
......@@ -36,6 +35,7 @@
#include "storage/proc.h"
#include "storage/sinval.h"
#include "storage/smgr.h"
#include "utils/flatfiles.h"
#include "utils/guc.h"
#include "utils/inval.h"
#include "utils/memutils.h"
......@@ -1354,6 +1354,7 @@ StartTransaction(void)
* start processing
*/
s->state = TRANS_START;
s->transactionId = InvalidTransactionId; /* until assigned */
/*
* Make sure we've freed any old snapshot, and reset xact state
......@@ -1464,9 +1465,9 @@ CommitTransaction(void)
/* NOTIFY commit must come before lower-level cleanup */
AtCommit_Notify();
/* Update the flat password file if we changed pg_shadow or pg_group */
/* Update flat files if we changed pg_database, pg_shadow or pg_group */
/* This should be the last step before commit */
AtEOXact_UpdatePasswordFile(true);
AtEOXact_UpdateFlatFiles(true);
/* Prevent cancel/die interrupt while cleaning up */
HOLD_INTERRUPTS();
......@@ -1654,9 +1655,13 @@ AbortTransaction(void)
AtAbort_Portals();
AtEOXact_LargeObject(false); /* 'false' means it's abort */
AtAbort_Notify();
AtEOXact_UpdatePasswordFile(false);
AtEOXact_UpdateFlatFiles(false);
/* Advertise the fact that we aborted in pg_clog. */
/*
* Advertise the fact that we aborted in pg_clog (assuming that we
* got as far as assigning an XID to advertise).
*/
if (TransactionIdIsValid(s->transactionId))
RecordTransactionAbort();
/*
......@@ -2033,11 +2038,26 @@ AbortCurrentTransaction(void)
TransactionState s = CurrentTransactionState;
switch (s->blockState)
{
case TBLOCK_DEFAULT:
if (s->state == TRANS_DEFAULT)
{
/* we are idle, so nothing to do */
}
else
{
/*
* we aren't in a transaction, so we do nothing.
* We can get here after an error during transaction start
* (state will be TRANS_START). Need to clean up the
* incompletely started transaction. First, adjust the
* low-level state to suppress warning message from
* AbortTransaction.
*/
case TBLOCK_DEFAULT:
if (s->state == TRANS_START)
s->state = TRANS_INPROGRESS;
AbortTransaction();
CleanupTransaction();
}
break;
/*
......@@ -3277,7 +3297,7 @@ CommitSubTransaction(void)
AtEOSubXact_LargeObject(true, s->subTransactionId,
s->parent->subTransactionId);
AtSubCommit_Notify();
AtEOSubXact_UpdatePasswordFile(true, s->subTransactionId,
AtEOSubXact_UpdateFlatFiles(true, s->subTransactionId,
s->parent->subTransactionId);
CallSubXactCallbacks(SUBXACT_EVENT_COMMIT_SUB, s->subTransactionId,
......@@ -3387,7 +3407,7 @@ AbortSubTransaction(void)
AtEOSubXact_LargeObject(false, s->subTransactionId,
s->parent->subTransactionId);
AtSubAbort_Notify();
AtEOSubXact_UpdatePasswordFile(false, s->subTransactionId,
AtEOSubXact_UpdateFlatFiles(false, s->subTransactionId,
s->parent->subTransactionId);
/* Advertise the fact that we aborted in pg_clog. */
......
......@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/bootstrap/bootstrap.c,v 1.198 2005/01/14 21:08:44 tgl Exp $
* $PostgreSQL: pgsql/src/backend/bootstrap/bootstrap.c,v 1.199 2005/02/20 02:21:31 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -39,6 +39,7 @@
#include "storage/proc.h"
#include "tcop/tcopprot.h"
#include "utils/builtins.h"
#include "utils/flatfiles.h"
#include "utils/fmgroids.h"
#include "utils/guc.h"
#include "utils/lsyscache.h"
......@@ -407,6 +408,7 @@ BootstrapMain(int argc, char *argv[])
bootstrap_signals();
StartupXLOG();
LoadFreeSpaceMap();
BuildFlatFiles(false);
proc_exit(0); /* startup done */
case BS_XLOG_BGWRITER:
......
......@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.149 2005/01/27 23:23:55 neilc Exp $
* $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.150 2005/02/20 02:21:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -39,6 +39,7 @@
#include "utils/acl.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/flatfiles.h"
#include "utils/fmgroids.h"
#include "utils/guc.h"
#include "utils/lsyscache.h"
......@@ -506,6 +507,11 @@ createdb(const CreatedbStmt *stmt)
/* Close pg_database, but keep exclusive lock till commit */
heap_close(pg_database_rel, NoLock);
/*
* Set flag to update flat database file at commit.
*/
database_file_update_needed();
}
......@@ -642,6 +648,11 @@ dropdb(const char *dbname)
/* Close pg_database, but keep exclusive lock till commit */
heap_close(pgdbrel, NoLock);
/*
* Set flag to update flat database file at commit.
*/
database_file_update_needed();
}
......@@ -741,6 +752,11 @@ RenameDatabase(const char *oldname, const char *newname)
/* Close pg_database, but keep exclusive lock till commit */
heap_close(rel, NoLock);
/*
* Set flag to update flat database file at commit.
*/
database_file_update_needed();
}
......@@ -834,6 +850,11 @@ AlterDatabaseSet(AlterDatabaseSetStmt *stmt)
/* Close pg_database, but keep exclusive lock till commit */
heap_close(rel, NoLock);
/*
* We don't bother updating the flat file since ALTER DATABASE SET
* doesn't affect it.
*/
}
......@@ -933,6 +954,11 @@ AlterDatabaseOwner(const char *dbname, AclId newOwnerSysId)
/* Close pg_database, but keep exclusive lock till commit */
heap_close(rel, NoLock);
/*
* We don't bother updating the flat file since ALTER DATABASE OWNER
* doesn't affect it.
*/
}
......
This diff is collapsed.
......@@ -13,7 +13,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.300 2005/02/15 03:50:07 momjian Exp $
* $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.301 2005/02/20 02:21:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -32,6 +32,7 @@
#include "catalog/namespace.h"
#include "catalog/pg_database.h"
#include "catalog/pg_index.h"
#include "commands/dbcommands.h"
#include "commands/vacuum.h"
#include "executor/executor.h"
#include "miscadmin.h"
......@@ -761,8 +762,13 @@ vac_update_dbstats(Oid dbid,
*
* Scan pg_database to determine the system-wide oldest datvacuumxid,
* and use it to truncate the transaction commit log (pg_clog).
* Also generate a warning if the system-wide oldest datfrozenxid
* seems to be in danger of wrapping around.
* Also update the XID wrap limit point maintained by varsup.c.
*
* We also generate a warning if the system-wide oldest datfrozenxid
* seems to be in danger of wrapping around. This is a long-in-advance
* warning; if we start getting uncomfortably close, GetNewTransactionId
* will generate more-annoying warnings, and ultimately refuse to issue
* any more new XIDs.
*
* The passed XIDs are simply the ones I just wrote into my pg_database
* entry. They're used to initialize the "min" calculations.
......@@ -778,10 +784,17 @@ vac_truncate_clog(TransactionId vacuumXID, TransactionId frozenXID)
HeapScanDesc scan;
HeapTuple tuple;
int32 age;
NameData oldest_datname;
bool vacuumAlreadyWrapped = false;
bool frozenAlreadyWrapped = false;
/* init oldest_datname to sync with my frozenXID */
namestrcpy(&oldest_datname, get_database_name(MyDatabaseId));
/*
* Note: the "already wrapped" cases should now be impossible due to the
* defenses in GetNewTransactionId, but we keep them anyway.
*/
relation = heap_openr(DatabaseRelationName, AccessShareLock);
scan = heap_beginscan(relation, SnapshotNow, 0, NULL);
......@@ -807,7 +820,10 @@ vac_truncate_clog(TransactionId vacuumXID, TransactionId frozenXID)
if (TransactionIdPrecedes(myXID, dbform->datfrozenxid))
frozenAlreadyWrapped = true;
else if (TransactionIdPrecedes(dbform->datfrozenxid, frozenXID))
{
frozenXID = dbform->datfrozenxid;
namecpy(&oldest_datname, &dbform->datname);
}
}
}
......@@ -830,24 +846,30 @@ vac_truncate_clog(TransactionId vacuumXID, TransactionId frozenXID)
/* Truncate CLOG to the oldest vacuumxid */
TruncateCLOG(vacuumXID);
/* Give warning about impending wraparound problems */
/*
* Do not update varsup.c if we seem to have suffered wraparound
* already; the computed XID might be bogus.
*/
if (frozenAlreadyWrapped)
{
ereport(WARNING,
(errmsg("some databases have not been vacuumed in over 1 billion transactions"),
errhint("Better vacuum them soon, or you may have a wraparound failure.")));
return;
}
else
{
/* Update the wrap limit for GetNewTransactionId */
SetTransactionIdLimit(frozenXID, &oldest_datname);
/* Give warning about impending wraparound problems */
age = (int32) (myXID - frozenXID);
if (age > (int32) ((MaxTransactionId >> 3) * 3))
ereport(WARNING,
(errmsg("some databases have not been vacuumed in %d transactions",
age),
errhint("Better vacuum them within %d transactions, "
"or you may have a wraparound failure.",
(int32) (MaxTransactionId >> 1) - age)));
}
(errmsg("database \"%s\" must be vacuumed within %u transactions",
NameStr(oldest_datname),
(MaxTransactionId >> 1) - age),
errhint("To avoid a database shutdown, execute a full-database VACUUM in \"%s\".",
NameStr(oldest_datname))));
}
......
......@@ -10,13 +10,12 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/libpq/hba.c,v 1.137 2005/02/12 23:53:42 momjian Exp $
* $PostgreSQL: pgsql/src/backend/libpq/hba.c,v 1.138 2005/02/20 02:21:40 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include <errno.h>
#include <pwd.h>
#include <fcntl.h>
#include <sys/param.h>
......@@ -29,12 +28,12 @@
#include <arpa/inet.h>
#include <unistd.h>
#include "commands/user.h"
#include "libpq/crypt.h"
#include "libpq/libpq.h"
#include "miscadmin.h"
#include "nodes/pg_list.h"
#include "storage/fd.h"
#include "utils/flatfiles.h"
#include "utils/guc.h"
......@@ -936,7 +935,7 @@ load_group(void)
group_length = 0;
/* Read in the file contents */
filename = group_getfilename();
filename = group_getflatfilename();
group_file = AllocateFile(filename, "r");
if (group_file == NULL)
......@@ -993,7 +992,7 @@ load_user(void)
user_length = 0;
/* Read in the file contents */
filename = user_getfilename();
filename = user_getflatfilename();
user_file = AllocateFile(filename, "r");
if (user_file == NULL)
......
......@@ -37,7 +37,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.443 2005/01/12 16:38:17 tgl Exp $
* $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.444 2005/02/20 02:21:54 tgl Exp $
*
* NOTES
*
......@@ -903,12 +903,10 @@ PostmasterMain(int argc, char *argv[])
pgstat_init();
/*
* Load cached files for client authentication.
* Load configuration files for client authentication.
*/
load_hba();
load_ident();
load_user();
load_group();
/*
* We're ready to rock and roll...
......@@ -1797,6 +1795,8 @@ SIGHUP_handler(SIGNAL_ARGS)
if (SysLoggerPID != 0)
kill(SysLoggerPID, SIGHUP);
/* PgStatPID does not currently need SIGHUP */
/* Reload authentication config files too */
load_hba();
load_ident();
......@@ -2006,6 +2006,14 @@ reaper(SIGNAL_ARGS)
*/
FatalError = false;
/*
* Load the flat user/group files into postmaster's caches.
* The startup process has recomputed these from the database
* contents, so we wait till it finishes before loading them.
*/
load_user();
load_group();
/*
* Crank up the background writer. It doesn't matter if this
* fails, we'll just try again later.
......@@ -2662,7 +2670,7 @@ BackendRun(Port *port)
port->remote_port = strdup(remote_port);
/*
* In EXEC_BACKEND case, we didn't inherit the contents of pg_hba.c
* In EXEC_BACKEND case, we didn't inherit the contents of pg_hba.conf
* etcetera from the postmaster, and have to load them ourselves.
* Build the PostmasterContext (which didn't exist before, in this
* process) to contain the data.
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.440 2004/12/31 22:01:16 pgsql Exp $
* $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.441 2005/02/20 02:21:57 tgl Exp $
*
* NOTES
* this is the "main" module of the postgres backend and
......@@ -55,6 +55,7 @@
#include "tcop/pquery.h"
#include "tcop/tcopprot.h"
#include "tcop/utility.h"
#include "utils/flatfiles.h"
#include "utils/guc.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
......@@ -2706,6 +2707,12 @@ PostgresMain(int argc, char *argv[], const char *username)
*/
LoadFreeSpaceMap();
on_shmem_exit(DumpFreeSpaceMap, 0);
/*
* We have to build the flat file for pg_database, but not for
* the user and group tables, since we won't try to do authentication.
*/
BuildFlatFiles(true);
}
/*
......
......@@ -4,7 +4,7 @@
# Makefile for utils/init
#
# IDENTIFICATION
# $PostgreSQL: pgsql/src/backend/utils/init/Makefile,v 1.17 2004/05/11 21:57:14 momjian Exp $
# $PostgreSQL: pgsql/src/backend/utils/init/Makefile,v 1.18 2005/02/20 02:22:00 tgl Exp $
#
#-------------------------------------------------------------------------
......@@ -12,7 +12,7 @@ subdir = src/backend/utils/init
top_builddir = ../../../..
include $(top_builddir)/src/Makefile.global
OBJS = globals.o miscinit.o postinit.o
OBJS = flatfiles.o globals.o miscinit.o postinit.o
all: SUBSYS.o
......
This diff is collapsed.
......@@ -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/access/transam.h,v 1.51 2004/12/31 22:03:21 pgsql Exp $
* $PostgreSQL: pgsql/src/include/access/transam.h,v 1.52 2005/02/20 02:22:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -75,13 +75,21 @@
/*
* VariableCache is placed in shmem and used by
* backends to get next available XID & OID.
* backends to get next available OID & XID.
*
* Note: xidWrapLimit and limit_datname are not "active" values, but are
* used just to generate useful messages when xidWarnLimit or xidStopLimit
* are exceeded.
*/
typedef struct VariableCacheData
{
TransactionId nextXid; /* next XID to assign */
Oid nextOid; /* next OID to assign */
uint32 oidCount; /* OIDs available before must do XLOG work */
TransactionId nextXid; /* next XID to assign */
TransactionId xidWarnLimit; /* start complaining here */
TransactionId xidStopLimit; /* refuse to advance nextXid beyond here */
TransactionId xidWrapLimit; /* where the world ends */
NameData limit_datname; /* database that needs vacuumed first */
} VariableCacheData;
typedef VariableCacheData *VariableCache;
......@@ -118,6 +126,8 @@ extern bool TransactionIdFollowsOrEquals(TransactionId id1, TransactionId id2);
/* in transam/varsup.c */
extern TransactionId GetNewTransactionId(bool isSubXact);
extern TransactionId ReadNewTransactionId(void);
extern void SetTransactionIdLimit(TransactionId oldest_datfrozenxid,
Name oldest_datname);
extern Oid GetNewObjectId(void);
extern void CheckMaxObjectId(Oid assigned_oid);
......
......@@ -4,20 +4,16 @@
* Commands for manipulating users and groups.
*
*
* $PostgreSQL: pgsql/src/include/commands/user.h,v 1.25 2004/09/16 16:58:39 tgl Exp $
* $PostgreSQL: pgsql/src/include/commands/user.h,v 1.26 2005/02/20 02:22:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef USER_H
#define USER_H
#include "fmgr.h"
#include "nodes/parsenodes.h"
extern char *group_getfilename(void);
extern char *user_getfilename(void);
extern void CreateUser(CreateUserStmt *stmt);
extern void AlterUser(AlterUserStmt *stmt);
extern void AlterUserSet(AlterUserSetStmt *stmt);
......@@ -29,11 +25,4 @@ extern void AlterGroup(AlterGroupStmt *stmt, const char *tag);
extern void DropGroup(DropGroupStmt *stmt);
extern void RenameGroup(const char *oldname, const char *newname);
extern Datum update_pg_pwd_and_pg_group(PG_FUNCTION_ARGS);
extern void AtEOXact_UpdatePasswordFile(bool isCommit);
extern void AtEOSubXact_UpdatePasswordFile(bool isCommit,
SubTransactionId mySubid,
SubTransactionId parentSubid);
#endif /* USER_H */
/*-------------------------------------------------------------------------
*
* flatfiles.h
* Routines for maintaining "flat file" images of the shared catalogs.
*
*
* $PostgreSQL: pgsql/src/include/utils/flatfiles.h,v 1.1 2005/02/20 02:22:07 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef FLATFILES_H
#define FLATFILES_H
#include "fmgr.h"
extern void database_file_update_needed(void);
extern void group_file_update_needed(void);
extern void user_file_update_needed(void);
extern char *database_getflatfilename(void);
extern char *group_getflatfilename(void);
extern char *user_getflatfilename(void);
extern void BuildFlatFiles(bool database_only);
extern void AtEOXact_UpdateFlatFiles(bool isCommit);
extern void AtEOSubXact_UpdateFlatFiles(bool isCommit,
SubTransactionId mySubid,
SubTransactionId parentSubid);
extern Datum flatfile_update_trigger(PG_FUNCTION_ARGS);
#endif /* FLATFILES_H */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment