Remove flatfiles.c, which is now obsolete.
Recent commits have removed the various uses it was supporting. It was a performance bottleneck, according to bug report #4919 by Lauris Ulmanis; seems it slowed down user creation after a billion users.
This commit is contained in:
parent
0905e8aeeb
commit
a8bb8eb583
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/access/transam/twophase_rmgr.c,v 1.8 2009/01/01 17:23:36 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/access/transam/twophase_rmgr.c,v 1.9 2009/09/01 02:54:51 alvherre Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -18,7 +18,6 @@
|
||||||
#include "commands/async.h"
|
#include "commands/async.h"
|
||||||
#include "pgstat.h"
|
#include "pgstat.h"
|
||||||
#include "storage/lock.h"
|
#include "storage/lock.h"
|
||||||
#include "utils/flatfiles.h"
|
|
||||||
#include "utils/inval.h"
|
#include "utils/inval.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -27,7 +26,6 @@ const TwoPhaseCallback twophase_recover_callbacks[TWOPHASE_RM_MAX_ID + 1] =
|
||||||
NULL, /* END ID */
|
NULL, /* END ID */
|
||||||
lock_twophase_recover, /* Lock */
|
lock_twophase_recover, /* Lock */
|
||||||
NULL, /* Inval */
|
NULL, /* Inval */
|
||||||
NULL, /* flat file update */
|
|
||||||
NULL, /* notify/listen */
|
NULL, /* notify/listen */
|
||||||
NULL /* pgstat */
|
NULL /* pgstat */
|
||||||
};
|
};
|
||||||
|
@ -37,7 +35,6 @@ const TwoPhaseCallback twophase_postcommit_callbacks[TWOPHASE_RM_MAX_ID + 1] =
|
||||||
NULL, /* END ID */
|
NULL, /* END ID */
|
||||||
lock_twophase_postcommit, /* Lock */
|
lock_twophase_postcommit, /* Lock */
|
||||||
inval_twophase_postcommit, /* Inval */
|
inval_twophase_postcommit, /* Inval */
|
||||||
flatfile_twophase_postcommit, /* flat file update */
|
|
||||||
notify_twophase_postcommit, /* notify/listen */
|
notify_twophase_postcommit, /* notify/listen */
|
||||||
pgstat_twophase_postcommit /* pgstat */
|
pgstat_twophase_postcommit /* pgstat */
|
||||||
};
|
};
|
||||||
|
@ -47,7 +44,6 @@ const TwoPhaseCallback twophase_postabort_callbacks[TWOPHASE_RM_MAX_ID + 1] =
|
||||||
NULL, /* END ID */
|
NULL, /* END ID */
|
||||||
lock_twophase_postabort, /* Lock */
|
lock_twophase_postabort, /* Lock */
|
||||||
NULL, /* Inval */
|
NULL, /* Inval */
|
||||||
NULL, /* flat file update */
|
|
||||||
NULL, /* notify/listen */
|
NULL, /* notify/listen */
|
||||||
pgstat_twophase_postabort /* pgstat */
|
pgstat_twophase_postabort /* pgstat */
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.274 2009/06/11 14:48:54 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.275 2009/09/01 02:54:51 alvherre Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -43,7 +43,6 @@
|
||||||
#include "storage/sinvaladt.h"
|
#include "storage/sinvaladt.h"
|
||||||
#include "storage/smgr.h"
|
#include "storage/smgr.h"
|
||||||
#include "utils/combocid.h"
|
#include "utils/combocid.h"
|
||||||
#include "utils/flatfiles.h"
|
|
||||||
#include "utils/guc.h"
|
#include "utils/guc.h"
|
||||||
#include "utils/inval.h"
|
#include "utils/inval.h"
|
||||||
#include "utils/memutils.h"
|
#include "utils/memutils.h"
|
||||||
|
@ -1608,12 +1607,6 @@ CommitTransaction(void)
|
||||||
/* NOTIFY commit must come before lower-level cleanup */
|
/* NOTIFY commit must come before lower-level cleanup */
|
||||||
AtCommit_Notify();
|
AtCommit_Notify();
|
||||||
|
|
||||||
/*
|
|
||||||
* Update flat files if we changed pg_database, pg_authid or
|
|
||||||
* pg_auth_members. This should be the last step before commit.
|
|
||||||
*/
|
|
||||||
AtEOXact_UpdateFlatFiles(true);
|
|
||||||
|
|
||||||
/* Prevent cancel/die interrupt while cleaning up */
|
/* Prevent cancel/die interrupt while cleaning up */
|
||||||
HOLD_INTERRUPTS();
|
HOLD_INTERRUPTS();
|
||||||
|
|
||||||
|
@ -1797,7 +1790,7 @@ PrepareTransaction(void)
|
||||||
/* close large objects before lower-level cleanup */
|
/* close large objects before lower-level cleanup */
|
||||||
AtEOXact_LargeObject(true);
|
AtEOXact_LargeObject(true);
|
||||||
|
|
||||||
/* NOTIFY and flatfiles will be handled below */
|
/* NOTIFY will be handled below */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Don't allow PREPARE TRANSACTION if we've accessed a temporary table in
|
* Don't allow PREPARE TRANSACTION if we've accessed a temporary table in
|
||||||
|
@ -1860,7 +1853,6 @@ PrepareTransaction(void)
|
||||||
StartPrepare(gxact);
|
StartPrepare(gxact);
|
||||||
|
|
||||||
AtPrepare_Notify();
|
AtPrepare_Notify();
|
||||||
AtPrepare_UpdateFlatFiles();
|
|
||||||
AtPrepare_Inval();
|
AtPrepare_Inval();
|
||||||
AtPrepare_Locks();
|
AtPrepare_Locks();
|
||||||
AtPrepare_PgStat();
|
AtPrepare_PgStat();
|
||||||
|
@ -1909,7 +1901,7 @@ PrepareTransaction(void)
|
||||||
/* Clean up the snapshot manager */
|
/* Clean up the snapshot manager */
|
||||||
AtEarlyCommit_Snapshot();
|
AtEarlyCommit_Snapshot();
|
||||||
|
|
||||||
/* notify and flatfiles don't need a postprepare call */
|
/* notify doesn't need a postprepare call */
|
||||||
|
|
||||||
PostPrepare_PgStat();
|
PostPrepare_PgStat();
|
||||||
|
|
||||||
|
@ -2036,7 +2028,6 @@ AbortTransaction(void)
|
||||||
AtAbort_Portals();
|
AtAbort_Portals();
|
||||||
AtEOXact_LargeObject(false); /* 'false' means it's abort */
|
AtEOXact_LargeObject(false); /* 'false' means it's abort */
|
||||||
AtAbort_Notify();
|
AtAbort_Notify();
|
||||||
AtEOXact_UpdateFlatFiles(false);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Advertise the fact that we aborted in pg_clog (assuming that we got as
|
* Advertise the fact that we aborted in pg_clog (assuming that we got as
|
||||||
|
@ -3764,8 +3755,6 @@ CommitSubTransaction(void)
|
||||||
AtEOSubXact_LargeObject(true, s->subTransactionId,
|
AtEOSubXact_LargeObject(true, s->subTransactionId,
|
||||||
s->parent->subTransactionId);
|
s->parent->subTransactionId);
|
||||||
AtSubCommit_Notify();
|
AtSubCommit_Notify();
|
||||||
AtEOSubXact_UpdateFlatFiles(true, s->subTransactionId,
|
|
||||||
s->parent->subTransactionId);
|
|
||||||
|
|
||||||
CallSubXactCallbacks(SUBXACT_EVENT_COMMIT_SUB, s->subTransactionId,
|
CallSubXactCallbacks(SUBXACT_EVENT_COMMIT_SUB, s->subTransactionId,
|
||||||
s->parent->subTransactionId);
|
s->parent->subTransactionId);
|
||||||
|
@ -3885,8 +3874,6 @@ AbortSubTransaction(void)
|
||||||
AtEOSubXact_LargeObject(false, s->subTransactionId,
|
AtEOSubXact_LargeObject(false, s->subTransactionId,
|
||||||
s->parent->subTransactionId);
|
s->parent->subTransactionId);
|
||||||
AtSubAbort_Notify();
|
AtSubAbort_Notify();
|
||||||
AtEOSubXact_UpdateFlatFiles(false, s->subTransactionId,
|
|
||||||
s->parent->subTransactionId);
|
|
||||||
|
|
||||||
/* Advertise the fact that we aborted in pg_clog. */
|
/* Advertise the fact that we aborted in pg_clog. */
|
||||||
(void) RecordTransactionAbort(true);
|
(void) RecordTransactionAbort(true);
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.350 2009/08/31 02:23:22 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.351 2009/09/01 02:54:51 alvherre Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -49,7 +49,6 @@
|
||||||
#include "storage/smgr.h"
|
#include "storage/smgr.h"
|
||||||
#include "storage/spin.h"
|
#include "storage/spin.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
#include "utils/flatfiles.h"
|
|
||||||
#include "utils/guc.h"
|
#include "utils/guc.h"
|
||||||
#include "utils/ps_status.h"
|
#include "utils/ps_status.h"
|
||||||
#include "pg_trace.h"
|
#include "pg_trace.h"
|
||||||
|
@ -8077,8 +8076,6 @@ StartupProcessMain(void)
|
||||||
|
|
||||||
StartupXLOG();
|
StartupXLOG();
|
||||||
|
|
||||||
BuildFlatFiles(false);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Exit normally. Exit code 0 tells postmaster that we completed recovery
|
* Exit normally. Exit code 0 tells postmaster that we completed recovery
|
||||||
* successfully.
|
* successfully.
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.225 2009/06/11 14:48:55 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.226 2009/09/01 02:54:51 alvherre Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -49,7 +49,6 @@
|
||||||
#include "storage/smgr.h"
|
#include "storage/smgr.h"
|
||||||
#include "utils/acl.h"
|
#include "utils/acl.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
#include "utils/flatfiles.h"
|
|
||||||
#include "utils/fmgroids.h"
|
#include "utils/fmgroids.h"
|
||||||
#include "utils/guc.h"
|
#include "utils/guc.h"
|
||||||
#include "utils/lsyscache.h"
|
#include "utils/lsyscache.h"
|
||||||
|
@ -691,19 +690,17 @@ createdb(const CreatedbStmt *stmt)
|
||||||
RequestCheckpoint(CHECKPOINT_IMMEDIATE | CHECKPOINT_FORCE | CHECKPOINT_WAIT);
|
RequestCheckpoint(CHECKPOINT_IMMEDIATE | CHECKPOINT_FORCE | CHECKPOINT_WAIT);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Close pg_database, but keep lock till commit (this is important to
|
* Close pg_database, but keep lock till commit.
|
||||||
* prevent any risk of deadlock failure while updating flat file)
|
|
||||||
*/
|
*/
|
||||||
heap_close(pg_database_rel, NoLock);
|
heap_close(pg_database_rel, NoLock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set flag to update flat database file at commit. Note: this also
|
* Force synchronous commit, thus minimizing the window between
|
||||||
* forces synchronous commit, which minimizes the window between
|
|
||||||
* creation of the database files and commital of the transaction. If
|
* creation of the database files and commital of the transaction. If
|
||||||
* we crash before committing, we'll have a DB that's taking up disk
|
* we crash before committing, we'll have a DB that's taking up disk
|
||||||
* space but is not in pg_database, which is not good.
|
* space but is not in pg_database, which is not good.
|
||||||
*/
|
*/
|
||||||
database_file_update_needed();
|
ForceSyncCommit();
|
||||||
}
|
}
|
||||||
PG_END_ENSURE_ERROR_CLEANUP(createdb_failure_callback,
|
PG_END_ENSURE_ERROR_CLEANUP(createdb_failure_callback,
|
||||||
PointerGetDatum(&fparms));
|
PointerGetDatum(&fparms));
|
||||||
|
@ -862,19 +859,17 @@ dropdb(const char *dbname, bool missing_ok)
|
||||||
remove_dbtablespaces(db_id);
|
remove_dbtablespaces(db_id);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Close pg_database, but keep lock till commit (this is important to
|
* Close pg_database, but keep lock till commit.
|
||||||
* prevent any risk of deadlock failure while updating flat file)
|
|
||||||
*/
|
*/
|
||||||
heap_close(pgdbrel, NoLock);
|
heap_close(pgdbrel, NoLock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set flag to update flat database file at commit. Note: this also
|
* Force synchronous commit, thus minimizing the window between removal
|
||||||
* forces synchronous commit, which minimizes the window between removal
|
|
||||||
* of the database files and commital of the transaction. If we crash
|
* of the database files and commital of the transaction. If we crash
|
||||||
* before committing, we'll have a DB that's gone on disk but still there
|
* before committing, we'll have a DB that's gone on disk but still there
|
||||||
* according to pg_database, which is not good.
|
* according to pg_database, which is not good.
|
||||||
*/
|
*/
|
||||||
database_file_update_needed();
|
ForceSyncCommit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -957,15 +952,9 @@ RenameDatabase(const char *oldname, const char *newname)
|
||||||
CatalogUpdateIndexes(rel, newtup);
|
CatalogUpdateIndexes(rel, newtup);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Close pg_database, but keep lock till commit (this is important to
|
* Close pg_database, but keep lock till commit.
|
||||||
* prevent any risk of deadlock failure while updating flat file)
|
|
||||||
*/
|
*/
|
||||||
heap_close(rel, NoLock);
|
heap_close(rel, NoLock);
|
||||||
|
|
||||||
/*
|
|
||||||
* Set flag to update flat database file at commit.
|
|
||||||
*/
|
|
||||||
database_file_update_needed();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1212,17 +1201,15 @@ movedb(const char *dbname, const char *tblspcname)
|
||||||
RequestCheckpoint(CHECKPOINT_IMMEDIATE | CHECKPOINT_FORCE | CHECKPOINT_WAIT);
|
RequestCheckpoint(CHECKPOINT_IMMEDIATE | CHECKPOINT_FORCE | CHECKPOINT_WAIT);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set flag to update flat database file at commit. Note: this also
|
* Force synchronous commit, thus minimizing the window between
|
||||||
* forces synchronous commit, which minimizes the window between
|
|
||||||
* copying the database files and commital of the transaction. If we
|
* copying the database files and commital of the transaction. If we
|
||||||
* crash before committing, we'll leave an orphaned set of files on
|
* crash before committing, we'll leave an orphaned set of files on
|
||||||
* disk, which is not fatal but not good either.
|
* disk, which is not fatal but not good either.
|
||||||
*/
|
*/
|
||||||
database_file_update_needed();
|
ForceSyncCommit();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Close pg_database, but keep lock till commit (this is important to
|
* Close pg_database, but keep lock till commit.
|
||||||
* prevent any risk of deadlock failure while updating flat file)
|
|
||||||
*/
|
*/
|
||||||
heap_close(pgdbrel, NoLock);
|
heap_close(pgdbrel, NoLock);
|
||||||
}
|
}
|
||||||
|
@ -1401,11 +1388,6 @@ AlterDatabase(AlterDatabaseStmt *stmt, bool isTopLevel)
|
||||||
|
|
||||||
/* Close pg_database, but keep lock till commit */
|
/* Close pg_database, but keep lock till commit */
|
||||||
heap_close(rel, NoLock);
|
heap_close(rel, NoLock);
|
||||||
|
|
||||||
/*
|
|
||||||
* We don't bother updating the flat file since the existing options for
|
|
||||||
* ALTER DATABASE don't affect it.
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1494,11 +1476,6 @@ AlterDatabaseSet(AlterDatabaseSetStmt *stmt)
|
||||||
|
|
||||||
/* Close pg_database, but keep lock till commit */
|
/* Close pg_database, but keep lock till commit */
|
||||||
heap_close(rel, NoLock);
|
heap_close(rel, NoLock);
|
||||||
|
|
||||||
/*
|
|
||||||
* We don't bother updating the flat file since ALTER DATABASE SET doesn't
|
|
||||||
* affect it.
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1608,11 +1585,6 @@ AlterDatabaseOwner(const char *dbname, Oid newOwnerId)
|
||||||
|
|
||||||
/* Close pg_database, but keep lock till commit */
|
/* Close pg_database, but keep lock till commit */
|
||||||
heap_close(rel, NoLock);
|
heap_close(rel, NoLock);
|
||||||
|
|
||||||
/*
|
|
||||||
* We don't bother updating the flat file since ALTER DATABASE OWNER
|
|
||||||
* doesn't affect it.
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/backend/commands/user.c,v 1.187 2009/06/11 14:48:56 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/commands/user.c,v 1.188 2009/09/01 02:54:51 alvherre Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -26,7 +26,6 @@
|
||||||
#include "storage/lmgr.h"
|
#include "storage/lmgr.h"
|
||||||
#include "utils/acl.h"
|
#include "utils/acl.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
#include "utils/flatfiles.h"
|
|
||||||
#include "utils/fmgroids.h"
|
#include "utils/fmgroids.h"
|
||||||
#include "utils/guc.h"
|
#include "utils/guc.h"
|
||||||
#include "utils/lsyscache.h"
|
#include "utils/lsyscache.h"
|
||||||
|
@ -385,15 +384,9 @@ CreateRole(CreateRoleStmt *stmt)
|
||||||
GetUserId(), false);
|
GetUserId(), false);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Close pg_authid, but keep lock till commit (this is important to
|
* Close pg_authid, but keep lock till commit.
|
||||||
* prevent any risk of deadlock failure while updating flat file)
|
|
||||||
*/
|
*/
|
||||||
heap_close(pg_authid_rel, NoLock);
|
heap_close(pg_authid_rel, NoLock);
|
||||||
|
|
||||||
/*
|
|
||||||
* Set flag to update flat auth file at commit.
|
|
||||||
*/
|
|
||||||
auth_file_update_needed();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -710,15 +703,9 @@ AlterRole(AlterRoleStmt *stmt)
|
||||||
false);
|
false);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Close pg_authid, but keep lock till commit (this is important to
|
* Close pg_authid, but keep lock till commit.
|
||||||
* prevent any risk of deadlock failure while updating flat file)
|
|
||||||
*/
|
*/
|
||||||
heap_close(pg_authid_rel, NoLock);
|
heap_close(pg_authid_rel, NoLock);
|
||||||
|
|
||||||
/*
|
|
||||||
* Set flag to update flat auth file at commit.
|
|
||||||
*/
|
|
||||||
auth_file_update_needed();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -808,7 +795,6 @@ AlterRoleSet(AlterRoleSetStmt *stmt)
|
||||||
CatalogUpdateIndexes(rel, newtuple);
|
CatalogUpdateIndexes(rel, newtuple);
|
||||||
|
|
||||||
ReleaseSysCache(oldtuple);
|
ReleaseSysCache(oldtuple);
|
||||||
/* needn't keep lock since we won't be updating the flat file */
|
|
||||||
heap_close(rel, RowExclusiveLock);
|
heap_close(rel, RowExclusiveLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -970,16 +956,10 @@ DropRole(DropRoleStmt *stmt)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now we can clean up; but keep locks until commit (to avoid possible
|
* Now we can clean up; but keep locks until commit.
|
||||||
* deadlock failure while updating flat file)
|
|
||||||
*/
|
*/
|
||||||
heap_close(pg_auth_members_rel, NoLock);
|
heap_close(pg_auth_members_rel, NoLock);
|
||||||
heap_close(pg_authid_rel, NoLock);
|
heap_close(pg_authid_rel, NoLock);
|
||||||
|
|
||||||
/*
|
|
||||||
* Set flag to update flat auth file at commit.
|
|
||||||
*/
|
|
||||||
auth_file_update_needed();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1092,15 +1072,9 @@ RenameRole(const char *oldname, const char *newname)
|
||||||
ReleaseSysCache(oldtuple);
|
ReleaseSysCache(oldtuple);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Close pg_authid, but keep lock till commit (this is important to
|
* Close pg_authid, but keep lock till commit.
|
||||||
* prevent any risk of deadlock failure while updating flat file)
|
|
||||||
*/
|
*/
|
||||||
heap_close(rel, NoLock);
|
heap_close(rel, NoLock);
|
||||||
|
|
||||||
/*
|
|
||||||
* Set flag to update flat auth file at commit.
|
|
||||||
*/
|
|
||||||
auth_file_update_needed();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1157,15 +1131,9 @@ GrantRole(GrantRoleStmt *stmt)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Close pg_authid, but keep lock till commit (this is important to
|
* Close pg_authid, but keep lock till commit.
|
||||||
* prevent any risk of deadlock failure while updating flat file)
|
|
||||||
*/
|
*/
|
||||||
heap_close(pg_authid_rel, NoLock);
|
heap_close(pg_authid_rel, NoLock);
|
||||||
|
|
||||||
/*
|
|
||||||
* Set flag to update flat auth file at commit.
|
|
||||||
*/
|
|
||||||
auth_file_update_needed();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1385,8 +1353,7 @@ AddRoleMems(const char *rolename, Oid roleid,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Close pg_authmem, but keep lock till commit (this is important to
|
* Close pg_authmem, but keep lock till commit.
|
||||||
* prevent any risk of deadlock failure while updating flat file)
|
|
||||||
*/
|
*/
|
||||||
heap_close(pg_authmem_rel, NoLock);
|
heap_close(pg_authmem_rel, NoLock);
|
||||||
}
|
}
|
||||||
|
@ -1498,8 +1465,7 @@ DelRoleMems(const char *rolename, Oid roleid,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Close pg_authmem, but keep lock till commit (this is important to
|
* Close pg_authmem, but keep lock till commit.
|
||||||
* prevent any risk of deadlock failure while updating flat file)
|
|
||||||
*/
|
*/
|
||||||
heap_close(pg_authmem_rel, NoLock);
|
heap_close(pg_authmem_rel, NoLock);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.391 2009/08/31 02:23:22 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.392 2009/09/01 02:54:51 alvherre Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -46,7 +46,6 @@
|
||||||
#include "storage/procarray.h"
|
#include "storage/procarray.h"
|
||||||
#include "utils/acl.h"
|
#include "utils/acl.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
#include "utils/flatfiles.h"
|
|
||||||
#include "utils/fmgroids.h"
|
#include "utils/fmgroids.h"
|
||||||
#include "utils/inval.h"
|
#include "utils/inval.h"
|
||||||
#include "utils/lsyscache.h"
|
#include "utils/lsyscache.h"
|
||||||
|
@ -893,16 +892,12 @@ vac_update_datfrozenxid(void)
|
||||||
heap_close(relation, RowExclusiveLock);
|
heap_close(relation, RowExclusiveLock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we were able to advance datfrozenxid, mark the flat-file copy of
|
* If we were able to advance datfrozenxid, see if we can truncate pg_clog.
|
||||||
* pg_database for update at commit, and see if we can truncate pg_clog.
|
* Also do it if the shared XID-wrap-limit info is stale.
|
||||||
* Also force update if the shared XID-wrap-limit info is stale.
|
|
||||||
*/
|
*/
|
||||||
if (dirty || !TransactionIdLimitIsValid())
|
if (dirty || !TransactionIdLimitIsValid())
|
||||||
{
|
|
||||||
database_file_update_needed();
|
|
||||||
vac_truncate_clog(newFrozenXid);
|
vac_truncate_clog(newFrozenXid);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/libpq/hba.c,v 1.189 2009/08/29 19:26:51 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/libpq/hba.c,v 1.190 2009/09/01 02:54:51 alvherre Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -1274,51 +1274,6 @@ load_hba(void)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* 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
|
|
||||||
* dbfrozenxid: gets database's frozen XID
|
|
||||||
*
|
|
||||||
* 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, TransactionId *dbfrozenxid)
|
|
||||||
{
|
|
||||||
char buf[MAX_TOKEN];
|
|
||||||
|
|
||||||
if (feof(fp))
|
|
||||||
return false;
|
|
||||||
if (!next_token(fp, buf, sizeof(buf)))
|
|
||||||
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);
|
|
||||||
next_token(fp, buf, sizeof(buf));
|
|
||||||
if (!isdigit((unsigned char) buf[0]))
|
|
||||||
elog(FATAL, "bad data in flat pg_database file");
|
|
||||||
*dbfrozenxid = atoxid(buf);
|
|
||||||
/* expect EOL next */
|
|
||||||
if (next_token(fp, buf, sizeof(buf)))
|
|
||||||
elog(FATAL, "bad data in flat pg_database file");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Process one line from the ident config file.
|
* Process one line from the ident config file.
|
||||||
*
|
*
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.572 2009/09/01 00:09:42 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.573 2009/09/01 02:54:51 alvherre Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* this is the "main" module of the postgres backend and
|
* this is the "main" module of the postgres backend and
|
||||||
|
@ -66,7 +66,6 @@
|
||||||
#include "tcop/pquery.h"
|
#include "tcop/pquery.h"
|
||||||
#include "tcop/tcopprot.h"
|
#include "tcop/tcopprot.h"
|
||||||
#include "tcop/utility.h"
|
#include "tcop/utility.h"
|
||||||
#include "utils/flatfiles.h"
|
|
||||||
#include "utils/lsyscache.h"
|
#include "utils/lsyscache.h"
|
||||||
#include "utils/memutils.h"
|
#include "utils/memutils.h"
|
||||||
#include "utils/ps_status.h"
|
#include "utils/ps_status.h"
|
||||||
|
@ -3280,12 +3279,6 @@ PostgresMain(int argc, char *argv[], const char *username)
|
||||||
*/
|
*/
|
||||||
StartupXLOG();
|
StartupXLOG();
|
||||||
on_shmem_exit(ShutdownXLOG, 0);
|
on_shmem_exit(ShutdownXLOG, 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
|
# Makefile for utils/init
|
||||||
#
|
#
|
||||||
# IDENTIFICATION
|
# IDENTIFICATION
|
||||||
# $PostgreSQL: pgsql/src/backend/utils/init/Makefile,v 1.22 2008/02/19 10:30:08 petere Exp $
|
# $PostgreSQL: pgsql/src/backend/utils/init/Makefile,v 1.23 2009/09/01 02:54:51 alvherre Exp $
|
||||||
#
|
#
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -12,6 +12,6 @@ subdir = src/backend/utils/init
|
||||||
top_builddir = ../../../..
|
top_builddir = ../../../..
|
||||||
include $(top_builddir)/src/Makefile.global
|
include $(top_builddir)/src/Makefile.global
|
||||||
|
|
||||||
OBJS = flatfiles.o globals.o miscinit.o postinit.o
|
OBJS = globals.o miscinit.o postinit.o
|
||||||
|
|
||||||
include $(top_srcdir)/src/backend/common.mk
|
include $(top_srcdir)/src/backend/common.mk
|
||||||
|
|
|
@ -1,931 +0,0 @@
|
||||||
/*-------------------------------------------------------------------------
|
|
||||||
*
|
|
||||||
* flatfiles.c
|
|
||||||
* Routines for maintaining "flat file" images of the shared catalogs.
|
|
||||||
*
|
|
||||||
* We use flat files so that the postmaster and not-yet-fully-started
|
|
||||||
* backends can look at the contents of pg_database, pg_authid, and
|
|
||||||
* pg_auth_members for authentication purposes. This module is
|
|
||||||
* responsible for keeping the flat-file images as nearly in sync with
|
|
||||||
* database reality as possible.
|
|
||||||
*
|
|
||||||
* The tricky part of the write_xxx_file() routines in this module is that
|
|
||||||
* they need to be able to operate in the context of the database startup
|
|
||||||
* process (which calls BuildFlatFiles()) as well as a normal backend.
|
|
||||||
* This means for example that we can't assume a fully functional relcache
|
|
||||||
* and we can't use syscaches at all. The major restriction imposed by
|
|
||||||
* all that is that there's no way to read an out-of-line-toasted datum,
|
|
||||||
* because the tuptoaster.c code is not prepared to cope with such an
|
|
||||||
* environment. Fortunately we can design the shared catalogs in such
|
|
||||||
* a way that this is OK.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
|
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
|
||||||
*
|
|
||||||
* $PostgreSQL: pgsql/src/backend/utils/init/flatfiles.c,v 1.39 2009/08/31 02:23:22 tgl Exp $
|
|
||||||
*
|
|
||||||
*-------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
#include "postgres.h"
|
|
||||||
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include "access/heapam.h"
|
|
||||||
#include "access/transam.h"
|
|
||||||
#include "access/twophase_rmgr.h"
|
|
||||||
#include "access/xact.h"
|
|
||||||
#include "access/xlogutils.h"
|
|
||||||
#include "catalog/pg_auth_members.h"
|
|
||||||
#include "catalog/pg_authid.h"
|
|
||||||
#include "catalog/pg_database.h"
|
|
||||||
#include "catalog/pg_namespace.h"
|
|
||||||
#include "catalog/pg_tablespace.h"
|
|
||||||
#include "commands/trigger.h"
|
|
||||||
#include "miscadmin.h"
|
|
||||||
#include "storage/bufmgr.h"
|
|
||||||
#include "storage/fd.h"
|
|
||||||
#include "storage/lmgr.h"
|
|
||||||
#include "storage/pmsignal.h"
|
|
||||||
#include "utils/builtins.h"
|
|
||||||
#include "utils/flatfiles.h"
|
|
||||||
#include "utils/resowner.h"
|
|
||||||
#include "utils/tqual.h"
|
|
||||||
|
|
||||||
|
|
||||||
/* Actual names of the flat files (within $PGDATA) */
|
|
||||||
#define DATABASE_FLAT_FILE "global/pg_database"
|
|
||||||
#define AUTH_FLAT_FILE "global/pg_auth"
|
|
||||||
|
|
||||||
/* Info bits in a flatfiles 2PC record */
|
|
||||||
#define FF_BIT_DATABASE 1
|
|
||||||
#define FF_BIT_AUTH 2
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The need-to-update-files flags are SubTransactionIds that show
|
|
||||||
* what level of the subtransaction tree requested the update. To register
|
|
||||||
* an update, the subtransaction saves its own SubTransactionId in the flag,
|
|
||||||
* unless the value was already set to a valid SubTransactionId (which implies
|
|
||||||
* that it or a parent level has already requested the same). If it aborts
|
|
||||||
* and the value is its SubTransactionId, it resets the flag to
|
|
||||||
* InvalidSubTransactionId. If it commits, it changes the value to its
|
|
||||||
* parent's SubTransactionId. This way the value is propagated up to the
|
|
||||||
* top-level transaction, which will update the files if a valid
|
|
||||||
* SubTransactionId is seen at top-level commit.
|
|
||||||
*/
|
|
||||||
static SubTransactionId database_file_update_subid = InvalidSubTransactionId;
|
|
||||||
static SubTransactionId auth_file_update_subid = InvalidSubTransactionId;
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Mark flat database file as needing an update (because pg_database changed)
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
database_file_update_needed(void)
|
|
||||||
{
|
|
||||||
if (database_file_update_subid == InvalidSubTransactionId)
|
|
||||||
database_file_update_subid = GetCurrentSubTransactionId();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Mark flat auth file as needing an update (because pg_authid or
|
|
||||||
* pg_auth_members changed)
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
auth_file_update_needed(void)
|
|
||||||
{
|
|
||||||
if (auth_file_update_subid == InvalidSubTransactionId)
|
|
||||||
auth_file_update_subid = GetCurrentSubTransactionId();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* database_getflatfilename --- get pathname of database file
|
|
||||||
*
|
|
||||||
* Note that result string is palloc'd, and should be freed by the caller.
|
|
||||||
* (This convention is not really needed anymore, since the relative path
|
|
||||||
* is fixed.)
|
|
||||||
*/
|
|
||||||
char *
|
|
||||||
database_getflatfilename(void)
|
|
||||||
{
|
|
||||||
return pstrdup(DATABASE_FLAT_FILE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* auth_getflatfilename --- get pathname of auth file
|
|
||||||
*
|
|
||||||
* Note that result string is palloc'd, and should be freed by the caller.
|
|
||||||
* (This convention is not really needed anymore, since the relative path
|
|
||||||
* is fixed.)
|
|
||||||
*/
|
|
||||||
char *
|
|
||||||
auth_getflatfilename(void)
|
|
||||||
{
|
|
||||||
return pstrdup(AUTH_FLAT_FILE);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* fputs_quote
|
|
||||||
*
|
|
||||||
* Outputs string in quotes, with double-quotes duplicated.
|
|
||||||
* We could use quote_ident(), but that expects a TEXT argument.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
fputs_quote(const char *str, FILE *fp)
|
|
||||||
{
|
|
||||||
fputc('"', fp);
|
|
||||||
while (*str)
|
|
||||||
{
|
|
||||||
fputc(*str, fp);
|
|
||||||
if (*str == '"')
|
|
||||||
fputc('"', fp);
|
|
||||||
str++;
|
|
||||||
}
|
|
||||||
fputc('"', fp);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* name_okay
|
|
||||||
*
|
|
||||||
* We must disallow newlines in role names because
|
|
||||||
* hba.c's parser won't handle fields split across lines, even if quoted.
|
|
||||||
*/
|
|
||||||
static bool
|
|
||||||
name_okay(const char *str)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
i = strcspn(str, "\r\n");
|
|
||||||
return (str[i] == '\0');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* write_database_file: update the flat database file
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
write_database_file(Relation drel)
|
|
||||||
{
|
|
||||||
char *filename,
|
|
||||||
*tempname;
|
|
||||||
int bufsize;
|
|
||||||
FILE *fp;
|
|
||||||
mode_t oumask;
|
|
||||||
HeapScanDesc scan;
|
|
||||||
HeapTuple tuple;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Create a temporary filename to be renamed later. This prevents the
|
|
||||||
* backend from clobbering the flat file while the postmaster might be
|
|
||||||
* reading from it.
|
|
||||||
*/
|
|
||||||
filename = database_getflatfilename();
|
|
||||||
bufsize = strlen(filename) + 12;
|
|
||||||
tempname = (char *) palloc(bufsize);
|
|
||||||
snprintf(tempname, bufsize, "%s.%d", filename, MyProcPid);
|
|
||||||
|
|
||||||
oumask = umask((mode_t) 077);
|
|
||||||
fp = AllocateFile(tempname, "w");
|
|
||||||
umask(oumask);
|
|
||||||
if (fp == NULL)
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode_for_file_access(),
|
|
||||||
errmsg("could not write to temporary file \"%s\": %m",
|
|
||||||
tempname)));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Read pg_database and write the file.
|
|
||||||
*/
|
|
||||||
scan = heap_beginscan(drel, SnapshotNow, 0, NULL);
|
|
||||||
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check for illegal characters in the database name.
|
|
||||||
*/
|
|
||||||
if (!name_okay(datname))
|
|
||||||
{
|
|
||||||
ereport(LOG,
|
|
||||||
(errmsg("invalid database name \"%s\"", datname)));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The file format is: "dbname" oid tablespace frozenxid
|
|
||||||
*
|
|
||||||
* 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\n",
|
|
||||||
datoid, dattablespace, datfrozenxid);
|
|
||||||
}
|
|
||||||
heap_endscan(scan);
|
|
||||||
|
|
||||||
if (FreeFile(fp))
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode_for_file_access(),
|
|
||||||
errmsg("could not write to temporary file \"%s\": %m",
|
|
||||||
tempname)));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Rename the temp file to its final name, deleting the old flat file. We
|
|
||||||
* expect that rename(2) is an atomic action.
|
|
||||||
*/
|
|
||||||
if (rename(tempname, filename))
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode_for_file_access(),
|
|
||||||
errmsg("could not rename file \"%s\" to \"%s\": %m",
|
|
||||||
tempname, filename)));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Support for write_auth_file
|
|
||||||
*
|
|
||||||
* The format for the flat auth file is
|
|
||||||
* "rolename" "password" "validuntil" "memberof" "memberof" ...
|
|
||||||
* Each role's line lists all the roles (groups) of which it is directly
|
|
||||||
* or indirectly a member, except for itself.
|
|
||||||
*
|
|
||||||
* The postmaster expects the file to be sorted by rolename. There is not
|
|
||||||
* any special ordering of the membership lists.
|
|
||||||
*
|
|
||||||
* To construct this information, we scan pg_authid and pg_auth_members,
|
|
||||||
* and build data structures in-memory before writing the file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
Oid roleid;
|
|
||||||
char *rolname;
|
|
||||||
char *rolpassword;
|
|
||||||
char *rolvaliduntil;
|
|
||||||
List *member_of;
|
|
||||||
} auth_entry;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
Oid roleid;
|
|
||||||
Oid memberid;
|
|
||||||
} authmem_entry;
|
|
||||||
|
|
||||||
|
|
||||||
/* qsort comparator for sorting auth_entry array by roleid */
|
|
||||||
static int
|
|
||||||
oid_compar(const void *a, const void *b)
|
|
||||||
{
|
|
||||||
const auth_entry *a_auth = (const auth_entry *) a;
|
|
||||||
const auth_entry *b_auth = (const auth_entry *) b;
|
|
||||||
|
|
||||||
if (a_auth->roleid < b_auth->roleid)
|
|
||||||
return -1;
|
|
||||||
if (a_auth->roleid > b_auth->roleid)
|
|
||||||
return 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* qsort comparator for sorting auth_entry array by rolname */
|
|
||||||
static int
|
|
||||||
name_compar(const void *a, const void *b)
|
|
||||||
{
|
|
||||||
const auth_entry *a_auth = (const auth_entry *) a;
|
|
||||||
const auth_entry *b_auth = (const auth_entry *) b;
|
|
||||||
|
|
||||||
return strcmp(a_auth->rolname, b_auth->rolname);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* qsort comparator for sorting authmem_entry array by memberid */
|
|
||||||
static int
|
|
||||||
mem_compar(const void *a, const void *b)
|
|
||||||
{
|
|
||||||
const authmem_entry *a_auth = (const authmem_entry *) a;
|
|
||||||
const authmem_entry *b_auth = (const authmem_entry *) b;
|
|
||||||
|
|
||||||
if (a_auth->memberid < b_auth->memberid)
|
|
||||||
return -1;
|
|
||||||
if (a_auth->memberid > b_auth->memberid)
|
|
||||||
return 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* write_auth_file: update the flat auth file
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
write_auth_file(Relation rel_authid, Relation rel_authmem)
|
|
||||||
{
|
|
||||||
char *filename,
|
|
||||||
*tempname;
|
|
||||||
int bufsize;
|
|
||||||
BlockNumber totalblocks;
|
|
||||||
FILE *fp;
|
|
||||||
mode_t oumask;
|
|
||||||
HeapScanDesc scan;
|
|
||||||
HeapTuple tuple;
|
|
||||||
int curr_role = 0;
|
|
||||||
int total_roles = 0;
|
|
||||||
int curr_mem = 0;
|
|
||||||
int total_mem = 0;
|
|
||||||
int est_rows;
|
|
||||||
auth_entry *auth_info;
|
|
||||||
authmem_entry *authmem_info;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Create a temporary filename to be renamed later. This prevents the
|
|
||||||
* backend from clobbering the flat file while the postmaster might be
|
|
||||||
* reading from it.
|
|
||||||
*/
|
|
||||||
filename = auth_getflatfilename();
|
|
||||||
bufsize = strlen(filename) + 12;
|
|
||||||
tempname = (char *) palloc(bufsize);
|
|
||||||
snprintf(tempname, bufsize, "%s.%d", filename, MyProcPid);
|
|
||||||
|
|
||||||
oumask = umask((mode_t) 077);
|
|
||||||
fp = AllocateFile(tempname, "w");
|
|
||||||
umask(oumask);
|
|
||||||
if (fp == NULL)
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode_for_file_access(),
|
|
||||||
errmsg("could not write to temporary file \"%s\": %m",
|
|
||||||
tempname)));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Read pg_authid and fill temporary data structures.
|
|
||||||
*/
|
|
||||||
totalblocks = RelationGetNumberOfBlocks(rel_authid);
|
|
||||||
totalblocks = totalblocks ? totalblocks : 1;
|
|
||||||
est_rows = totalblocks * (BLCKSZ / (sizeof(HeapTupleHeaderData) + sizeof(FormData_pg_authid)));
|
|
||||||
auth_info = (auth_entry *) palloc(est_rows * sizeof(auth_entry));
|
|
||||||
|
|
||||||
scan = heap_beginscan(rel_authid, SnapshotNow, 0, NULL);
|
|
||||||
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
|
|
||||||
{
|
|
||||||
Form_pg_authid aform = (Form_pg_authid) GETSTRUCT(tuple);
|
|
||||||
HeapTupleHeader tup = tuple->t_data;
|
|
||||||
char *tp; /* ptr to tuple data */
|
|
||||||
long off; /* offset in tuple data */
|
|
||||||
bits8 *bp = tup->t_bits; /* ptr to null bitmask in tuple */
|
|
||||||
Datum datum;
|
|
||||||
|
|
||||||
if (curr_role >= est_rows)
|
|
||||||
{
|
|
||||||
est_rows *= 2;
|
|
||||||
auth_info = (auth_entry *)
|
|
||||||
repalloc(auth_info, est_rows * sizeof(auth_entry));
|
|
||||||
}
|
|
||||||
|
|
||||||
auth_info[curr_role].roleid = HeapTupleGetOid(tuple);
|
|
||||||
auth_info[curr_role].rolname = pstrdup(NameStr(aform->rolname));
|
|
||||||
auth_info[curr_role].member_of = NIL;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We can't use heap_getattr() here because during startup we will not
|
|
||||||
* have any tupdesc for pg_authid. Fortunately it's not too hard to
|
|
||||||
* work around this. rolpassword is the first possibly-null field so
|
|
||||||
* we can compute its offset directly. Note that this only works
|
|
||||||
* reliably because the preceding field (rolconnlimit) is int4, and
|
|
||||||
* therefore rolpassword is always 4-byte-aligned, and will be at the
|
|
||||||
* same offset no matter whether it uses 1-byte or 4-byte header.
|
|
||||||
*/
|
|
||||||
tp = (char *) tup + tup->t_hoff;
|
|
||||||
off = offsetof(FormData_pg_authid, rolpassword);
|
|
||||||
|
|
||||||
if (HeapTupleHasNulls(tuple) &&
|
|
||||||
att_isnull(Anum_pg_authid_rolpassword - 1, bp))
|
|
||||||
{
|
|
||||||
/* passwd is null, emit as an empty string */
|
|
||||||
auth_info[curr_role].rolpassword = pstrdup("");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* assume passwd is pass-by-ref */
|
|
||||||
datum = PointerGetDatum(tp + off);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The password probably shouldn't ever be out-of-line toasted; if
|
|
||||||
* it is, ignore it, since we can't handle that in startup mode.
|
|
||||||
*
|
|
||||||
* It is entirely likely that it's 1-byte format not 4-byte, and
|
|
||||||
* theoretically possible that it's compressed inline, but
|
|
||||||
* text_to_cstring should be able to handle those cases even in
|
|
||||||
* startup mode.
|
|
||||||
*/
|
|
||||||
if (VARATT_IS_EXTERNAL(DatumGetPointer(datum)))
|
|
||||||
auth_info[curr_role].rolpassword = pstrdup("");
|
|
||||||
else
|
|
||||||
auth_info[curr_role].rolpassword = TextDatumGetCString(datum);
|
|
||||||
|
|
||||||
/* assume passwd has attlen -1 */
|
|
||||||
off = att_addlength_pointer(off, -1, tp + off);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (HeapTupleHasNulls(tuple) &&
|
|
||||||
att_isnull(Anum_pg_authid_rolvaliduntil - 1, bp))
|
|
||||||
{
|
|
||||||
/* rolvaliduntil is null, emit as an empty string */
|
|
||||||
auth_info[curr_role].rolvaliduntil = pstrdup("");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TimestampTz *rvup;
|
|
||||||
|
|
||||||
/* Assume timestamptz has double alignment */
|
|
||||||
off = att_align_nominal(off, 'd');
|
|
||||||
rvup = (TimestampTz *) (tp + off);
|
|
||||||
auth_info[curr_role].rolvaliduntil =
|
|
||||||
DatumGetCString(DirectFunctionCall1(timestamptz_out,
|
|
||||||
TimestampTzGetDatum(*rvup)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check for illegal characters in the user name and password.
|
|
||||||
*/
|
|
||||||
if (!name_okay(auth_info[curr_role].rolname))
|
|
||||||
{
|
|
||||||
ereport(LOG,
|
|
||||||
(errmsg("invalid role name \"%s\"",
|
|
||||||
auth_info[curr_role].rolname)));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!name_okay(auth_info[curr_role].rolpassword))
|
|
||||||
{
|
|
||||||
ereport(LOG,
|
|
||||||
(errmsg("invalid role password \"%s\"",
|
|
||||||
auth_info[curr_role].rolpassword)));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
curr_role++;
|
|
||||||
total_roles++;
|
|
||||||
}
|
|
||||||
heap_endscan(scan);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Read pg_auth_members into temporary data structure, too
|
|
||||||
*/
|
|
||||||
totalblocks = RelationGetNumberOfBlocks(rel_authmem);
|
|
||||||
totalblocks = totalblocks ? totalblocks : 1;
|
|
||||||
est_rows = totalblocks * (BLCKSZ / (sizeof(HeapTupleHeaderData) + sizeof(FormData_pg_auth_members)));
|
|
||||||
authmem_info = (authmem_entry *) palloc(est_rows * sizeof(authmem_entry));
|
|
||||||
|
|
||||||
scan = heap_beginscan(rel_authmem, SnapshotNow, 0, NULL);
|
|
||||||
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
|
|
||||||
{
|
|
||||||
Form_pg_auth_members memform = (Form_pg_auth_members) GETSTRUCT(tuple);
|
|
||||||
|
|
||||||
if (curr_mem >= est_rows)
|
|
||||||
{
|
|
||||||
est_rows *= 2;
|
|
||||||
authmem_info = (authmem_entry *)
|
|
||||||
repalloc(authmem_info, est_rows * sizeof(authmem_entry));
|
|
||||||
}
|
|
||||||
|
|
||||||
authmem_info[curr_mem].roleid = memform->roleid;
|
|
||||||
authmem_info[curr_mem].memberid = memform->member;
|
|
||||||
curr_mem++;
|
|
||||||
total_mem++;
|
|
||||||
}
|
|
||||||
heap_endscan(scan);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Search for memberships. We can skip all this if pg_auth_members is
|
|
||||||
* empty.
|
|
||||||
*/
|
|
||||||
if (total_mem > 0)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Sort auth_info by roleid and authmem_info by memberid.
|
|
||||||
*/
|
|
||||||
qsort(auth_info, total_roles, sizeof(auth_entry), oid_compar);
|
|
||||||
qsort(authmem_info, total_mem, sizeof(authmem_entry), mem_compar);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* For each role, find what it belongs to.
|
|
||||||
*/
|
|
||||||
for (curr_role = 0; curr_role < total_roles; curr_role++)
|
|
||||||
{
|
|
||||||
List *roles_list;
|
|
||||||
List *roles_names_list = NIL;
|
|
||||||
ListCell *mem;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This search algorithm is the same as in is_member_of_role; we
|
|
||||||
* are just working with a different input data structure.
|
|
||||||
*/
|
|
||||||
roles_list = list_make1_oid(auth_info[curr_role].roleid);
|
|
||||||
|
|
||||||
foreach(mem, roles_list)
|
|
||||||
{
|
|
||||||
authmem_entry key;
|
|
||||||
authmem_entry *found_mem;
|
|
||||||
int first_found,
|
|
||||||
last_found,
|
|
||||||
i;
|
|
||||||
|
|
||||||
key.memberid = lfirst_oid(mem);
|
|
||||||
found_mem = bsearch(&key, authmem_info, total_mem,
|
|
||||||
sizeof(authmem_entry), mem_compar);
|
|
||||||
if (!found_mem)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* bsearch found a match for us; but if there were multiple
|
|
||||||
* matches it could have found any one of them. Locate first
|
|
||||||
* and last match.
|
|
||||||
*/
|
|
||||||
first_found = last_found = (found_mem - authmem_info);
|
|
||||||
while (first_found > 0 &&
|
|
||||||
mem_compar(&key, &authmem_info[first_found - 1]) == 0)
|
|
||||||
first_found--;
|
|
||||||
while (last_found + 1 < total_mem &&
|
|
||||||
mem_compar(&key, &authmem_info[last_found + 1]) == 0)
|
|
||||||
last_found++;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Now add all the new roles to roles_list.
|
|
||||||
*/
|
|
||||||
for (i = first_found; i <= last_found; i++)
|
|
||||||
roles_list = list_append_unique_oid(roles_list,
|
|
||||||
authmem_info[i].roleid);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
for_each_cell(mem, lnext(list_head(roles_list)))
|
|
||||||
{
|
|
||||||
auth_entry key_auth;
|
|
||||||
auth_entry *found_role;
|
|
||||||
|
|
||||||
key_auth.roleid = lfirst_oid(mem);
|
|
||||||
found_role = bsearch(&key_auth, auth_info, total_roles,
|
|
||||||
sizeof(auth_entry), oid_compar);
|
|
||||||
if (found_role) /* paranoia */
|
|
||||||
roles_names_list = lappend(roles_names_list,
|
|
||||||
found_role->rolname);
|
|
||||||
}
|
|
||||||
auth_info[curr_role].member_of = roles_names_list;
|
|
||||||
list_free(roles_list);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Now sort auth_info into rolname order for output, and write the file.
|
|
||||||
*/
|
|
||||||
qsort(auth_info, total_roles, sizeof(auth_entry), name_compar);
|
|
||||||
|
|
||||||
for (curr_role = 0; curr_role < total_roles; curr_role++)
|
|
||||||
{
|
|
||||||
auth_entry *arole = &auth_info[curr_role];
|
|
||||||
ListCell *mem;
|
|
||||||
|
|
||||||
fputs_quote(arole->rolname, fp);
|
|
||||||
fputs(" ", fp);
|
|
||||||
fputs_quote(arole->rolpassword, fp);
|
|
||||||
fputs(" ", fp);
|
|
||||||
fputs_quote(arole->rolvaliduntil, fp);
|
|
||||||
|
|
||||||
foreach(mem, arole->member_of)
|
|
||||||
{
|
|
||||||
fputs(" ", fp);
|
|
||||||
fputs_quote((char *) lfirst(mem), fp);
|
|
||||||
}
|
|
||||||
|
|
||||||
fputs("\n", fp);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FreeFile(fp))
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode_for_file_access(),
|
|
||||||
errmsg("could not write to temporary file \"%s\": %m",
|
|
||||||
tempname)));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Rename the temp file to its final name, deleting the old flat file. We
|
|
||||||
* expect that rename(2) is an atomic action.
|
|
||||||
*/
|
|
||||||
if (rename(tempname, filename))
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode_for_file_access(),
|
|
||||||
errmsg("could not rename file \"%s\" to \"%s\": %m",
|
|
||||||
tempname, filename)));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This routine is called once during database startup, after completing
|
|
||||||
* WAL replay if needed. Its purpose is to sync the flat files with the
|
|
||||||
* current state of the database tables. This is particularly important
|
|
||||||
* during PITR operation, since the flat files will come from the
|
|
||||||
* base backup which may be far out of sync with the current state.
|
|
||||||
*
|
|
||||||
* In theory we could skip rebuilding the flat files if no WAL replay
|
|
||||||
* occurred, but it seems best to just do it always. We have to
|
|
||||||
* scan pg_database to compute the XID wrap limit anyway. Also, this
|
|
||||||
* policy means we need not force initdb to change the format of the
|
|
||||||
* flat files.
|
|
||||||
*
|
|
||||||
* In a standalone backend we pass database_only = true to skip processing
|
|
||||||
* the auth file. We won't need it, and building it could fail if there's
|
|
||||||
* something corrupt in the authid/authmem catalogs.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
BuildFlatFiles(bool database_only)
|
|
||||||
{
|
|
||||||
ResourceOwner owner;
|
|
||||||
RelFileNode rnode;
|
|
||||||
Relation rel_db,
|
|
||||||
rel_authid,
|
|
||||||
rel_authmem;
|
|
||||||
|
|
||||||
/* Need a resowner to keep the heapam and buffer code happy */
|
|
||||||
owner = ResourceOwnerCreate(NULL, "BuildFlatFiles");
|
|
||||||
CurrentResourceOwner = owner;
|
|
||||||
|
|
||||||
/* hard-wired path to pg_database */
|
|
||||||
rnode.spcNode = GLOBALTABLESPACE_OID;
|
|
||||||
rnode.dbNode = 0;
|
|
||||||
rnode.relNode = DatabaseRelationId;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We don't have any hope of running a real relcache, but we can use the
|
|
||||||
* same fake-relcache facility that WAL replay uses.
|
|
||||||
*
|
|
||||||
* No locking is needed because no one else is alive yet.
|
|
||||||
*/
|
|
||||||
rel_db = CreateFakeRelcacheEntry(rnode);
|
|
||||||
write_database_file(rel_db);
|
|
||||||
FreeFakeRelcacheEntry(rel_db);
|
|
||||||
|
|
||||||
if (!database_only)
|
|
||||||
{
|
|
||||||
/* hard-wired path to pg_authid */
|
|
||||||
rnode.spcNode = GLOBALTABLESPACE_OID;
|
|
||||||
rnode.dbNode = 0;
|
|
||||||
rnode.relNode = AuthIdRelationId;
|
|
||||||
rel_authid = CreateFakeRelcacheEntry(rnode);
|
|
||||||
|
|
||||||
/* hard-wired path to pg_auth_members */
|
|
||||||
rnode.spcNode = GLOBALTABLESPACE_OID;
|
|
||||||
rnode.dbNode = 0;
|
|
||||||
rnode.relNode = AuthMemRelationId;
|
|
||||||
rel_authmem = CreateFakeRelcacheEntry(rnode);
|
|
||||||
|
|
||||||
write_auth_file(rel_authid, rel_authmem);
|
|
||||||
FreeFakeRelcacheEntry(rel_authid);
|
|
||||||
FreeFakeRelcacheEntry(rel_authmem);
|
|
||||||
}
|
|
||||||
|
|
||||||
CurrentResourceOwner = NULL;
|
|
||||||
ResourceOwnerDelete(owner);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This routine is called during transaction commit or abort.
|
|
||||||
*
|
|
||||||
* On commit, if we've written any of the critical database tables during
|
|
||||||
* the current transaction, update the flat files and signal the postmaster.
|
|
||||||
*
|
|
||||||
* On abort, just reset the static flags so we don't try to do it on the
|
|
||||||
* next successful commit.
|
|
||||||
*
|
|
||||||
* NB: this should be the last step before actual transaction commit.
|
|
||||||
* If any error aborts the transaction after we run this code, the postmaster
|
|
||||||
* will still have received and cached the changed data; so minimize the
|
|
||||||
* window for such problems.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
AtEOXact_UpdateFlatFiles(bool isCommit)
|
|
||||||
{
|
|
||||||
Relation drel = NULL;
|
|
||||||
Relation arel = NULL;
|
|
||||||
Relation mrel = NULL;
|
|
||||||
|
|
||||||
if (database_file_update_subid == InvalidSubTransactionId &&
|
|
||||||
auth_file_update_subid == InvalidSubTransactionId)
|
|
||||||
return; /* nothing to do */
|
|
||||||
|
|
||||||
if (!isCommit)
|
|
||||||
{
|
|
||||||
database_file_update_subid = InvalidSubTransactionId;
|
|
||||||
auth_file_update_subid = InvalidSubTransactionId;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Advance command counter to be certain we see all effects of the current
|
|
||||||
* transaction.
|
|
||||||
*/
|
|
||||||
CommandCounterIncrement();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Open and lock the needed catalog(s).
|
|
||||||
*
|
|
||||||
* 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, AccessShareLock);
|
|
||||||
|
|
||||||
if (auth_file_update_subid != InvalidSubTransactionId)
|
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
database_file_update_subid = InvalidSubTransactionId;
|
|
||||||
write_database_file(drel);
|
|
||||||
heap_close(drel, NoLock);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (auth_file_update_subid != InvalidSubTransactionId)
|
|
||||||
{
|
|
||||||
auth_file_update_subid = InvalidSubTransactionId;
|
|
||||||
write_auth_file(arel, mrel);
|
|
||||||
heap_close(arel, NoLock);
|
|
||||||
heap_close(mrel, NoLock);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Force synchronous commit, to minimize the window between changing the
|
|
||||||
* flat files on-disk and marking the transaction committed. It's not
|
|
||||||
* great that there is any window at all, but definitely we don't want to
|
|
||||||
* make it larger than necessary.
|
|
||||||
*/
|
|
||||||
ForceSyncCommit();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This routine is called during transaction prepare.
|
|
||||||
*
|
|
||||||
* Record which files need to be refreshed if this transaction later
|
|
||||||
* commits.
|
|
||||||
*
|
|
||||||
* Note: it's OK to clear the flags immediately, since if the PREPARE fails
|
|
||||||
* further on, we'd only reset the flags anyway. So there's no need for a
|
|
||||||
* separate PostPrepare call.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
AtPrepare_UpdateFlatFiles(void)
|
|
||||||
{
|
|
||||||
uint16 info = 0;
|
|
||||||
|
|
||||||
if (database_file_update_subid != InvalidSubTransactionId)
|
|
||||||
{
|
|
||||||
database_file_update_subid = InvalidSubTransactionId;
|
|
||||||
info |= FF_BIT_DATABASE;
|
|
||||||
}
|
|
||||||
if (auth_file_update_subid != InvalidSubTransactionId)
|
|
||||||
{
|
|
||||||
auth_file_update_subid = InvalidSubTransactionId;
|
|
||||||
info |= FF_BIT_AUTH;
|
|
||||||
}
|
|
||||||
if (info != 0)
|
|
||||||
RegisterTwoPhaseRecord(TWOPHASE_RM_FLATFILES_ID, info,
|
|
||||||
NULL, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* AtEOSubXact_UpdateFlatFiles
|
|
||||||
*
|
|
||||||
* Called at subtransaction end, this routine resets or updates the
|
|
||||||
* need-to-update-files flags.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
AtEOSubXact_UpdateFlatFiles(bool isCommit,
|
|
||||||
SubTransactionId mySubid,
|
|
||||||
SubTransactionId parentSubid)
|
|
||||||
{
|
|
||||||
if (isCommit)
|
|
||||||
{
|
|
||||||
if (database_file_update_subid == mySubid)
|
|
||||||
database_file_update_subid = parentSubid;
|
|
||||||
|
|
||||||
if (auth_file_update_subid == mySubid)
|
|
||||||
auth_file_update_subid = parentSubid;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (database_file_update_subid == mySubid)
|
|
||||||
database_file_update_subid = InvalidSubTransactionId;
|
|
||||||
|
|
||||||
if (auth_file_update_subid == mySubid)
|
|
||||||
auth_file_update_subid = InvalidSubTransactionId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This trigger is fired whenever someone modifies pg_database, pg_authid
|
|
||||||
* or pg_auth_members via general-purpose INSERT/UPDATE/DELETE commands.
|
|
||||||
*
|
|
||||||
* It is sufficient for this to be a STATEMENT trigger since we don't
|
|
||||||
* care which individual rows changed. It doesn't much matter whether
|
|
||||||
* it's a BEFORE or AFTER trigger.
|
|
||||||
*/
|
|
||||||
Datum
|
|
||||||
flatfile_update_trigger(PG_FUNCTION_ARGS)
|
|
||||||
{
|
|
||||||
TriggerData *trigdata = (TriggerData *) fcinfo->context;
|
|
||||||
|
|
||||||
if (!CALLED_AS_TRIGGER(fcinfo))
|
|
||||||
elog(ERROR,
|
|
||||||
"flatfile_update_trigger was not called by trigger manager");
|
|
||||||
|
|
||||||
if (RelationGetNamespace(trigdata->tg_relation) != PG_CATALOG_NAMESPACE)
|
|
||||||
elog(ERROR, "flatfile_update_trigger was called for wrong table");
|
|
||||||
|
|
||||||
switch (RelationGetRelid(trigdata->tg_relation))
|
|
||||||
{
|
|
||||||
case DatabaseRelationId:
|
|
||||||
database_file_update_needed();
|
|
||||||
break;
|
|
||||||
case AuthIdRelationId:
|
|
||||||
case AuthMemRelationId:
|
|
||||||
auth_file_update_needed();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
elog(ERROR, "flatfile_update_trigger was called for wrong table");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return PointerGetDatum(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 2PC processing routine for COMMIT PREPARED case.
|
|
||||||
*
|
|
||||||
* (We don't have to do anything for ROLLBACK PREPARED.)
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
flatfile_twophase_postcommit(TransactionId xid, uint16 info,
|
|
||||||
void *recdata, uint32 len)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Set flags to do the needed file updates at the end of my own current
|
|
||||||
* transaction. (XXX this has some issues if my own transaction later
|
|
||||||
* rolls back, or if there is any significant delay before I commit. OK
|
|
||||||
* for now because we disallow COMMIT PREPARED inside a transaction
|
|
||||||
* block.)
|
|
||||||
*/
|
|
||||||
if (info & FF_BIT_DATABASE)
|
|
||||||
database_file_update_needed();
|
|
||||||
if (info & FF_BIT_AUTH)
|
|
||||||
auth_file_update_needed();
|
|
||||||
}
|
|
|
@ -42,7 +42,7 @@
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
* Portions taken from FreeBSD.
|
* Portions taken from FreeBSD.
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/bin/initdb/initdb.c,v 1.172 2009/06/11 14:49:07 momjian Exp $
|
* $PostgreSQL: pgsql/src/bin/initdb/initdb.c,v 1.173 2009/09/01 02:54:52 alvherre Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -1404,20 +1404,6 @@ setup_auth(void)
|
||||||
PG_CMD_DECL;
|
PG_CMD_DECL;
|
||||||
const char **line;
|
const char **line;
|
||||||
static const char *pg_authid_setup[] = {
|
static const char *pg_authid_setup[] = {
|
||||||
/*
|
|
||||||
* Create triggers to ensure manual updates to shared catalogs will be
|
|
||||||
* reflected into their "flat file" copies.
|
|
||||||
*/
|
|
||||||
"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_authid "
|
|
||||||
" AFTER INSERT OR UPDATE OR DELETE ON pg_authid "
|
|
||||||
" FOR EACH STATEMENT EXECUTE PROCEDURE flatfile_update_trigger();\n",
|
|
||||||
"CREATE TRIGGER pg_sync_pg_auth_members "
|
|
||||||
" AFTER INSERT OR UPDATE OR DELETE ON pg_auth_members "
|
|
||||||
" FOR EACH STATEMENT EXECUTE PROCEDURE flatfile_update_trigger();\n",
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The authid table shouldn't be readable except through views, to
|
* The authid table shouldn't be readable except through views, to
|
||||||
* ensure passwords are not publicly visible.
|
* ensure passwords are not publicly visible.
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/access/twophase_rmgr.h,v 1.7 2009/01/01 17:23:56 momjian Exp $
|
* $PostgreSQL: pgsql/src/include/access/twophase_rmgr.h,v 1.8 2009/09/01 02:54:52 alvherre Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -24,9 +24,8 @@ typedef uint8 TwoPhaseRmgrId;
|
||||||
#define TWOPHASE_RM_END_ID 0
|
#define TWOPHASE_RM_END_ID 0
|
||||||
#define TWOPHASE_RM_LOCK_ID 1
|
#define TWOPHASE_RM_LOCK_ID 1
|
||||||
#define TWOPHASE_RM_INVAL_ID 2
|
#define TWOPHASE_RM_INVAL_ID 2
|
||||||
#define TWOPHASE_RM_FLATFILES_ID 3
|
#define TWOPHASE_RM_NOTIFY_ID 3
|
||||||
#define TWOPHASE_RM_NOTIFY_ID 4
|
#define TWOPHASE_RM_PGSTAT_ID 4
|
||||||
#define TWOPHASE_RM_PGSTAT_ID 5
|
|
||||||
#define TWOPHASE_RM_MAX_ID TWOPHASE_RM_PGSTAT_ID
|
#define TWOPHASE_RM_MAX_ID TWOPHASE_RM_PGSTAT_ID
|
||||||
|
|
||||||
extern const TwoPhaseCallback twophase_recover_callbacks[];
|
extern const TwoPhaseCallback twophase_recover_callbacks[];
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.549 2009/08/04 04:04:12 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.550 2009/09/01 02:54:52 alvherre Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* The script catalog/genbki.sh reads this file and generates .bki
|
* The script catalog/genbki.sh reads this file and generates .bki
|
||||||
|
@ -2182,9 +2182,6 @@ DESCR("matches LIKE expression, case-insensitive");
|
||||||
DATA(insert OID = 1661 ( bpcharicnlike PGNSP PGUID 12 1 0 0 f f f t f i 2 0 16 "1042 25" _null_ _null_ _null_ _null_ texticnlike _null_ _null_ _null_ ));
|
DATA(insert OID = 1661 ( bpcharicnlike PGNSP PGUID 12 1 0 0 f f f t f i 2 0 16 "1042 25" _null_ _null_ _null_ _null_ texticnlike _null_ _null_ _null_ ));
|
||||||
DESCR("does not match LIKE expression, case-insensitive");
|
DESCR("does not match LIKE expression, case-insensitive");
|
||||||
|
|
||||||
DATA(insert OID = 1689 ( flatfile_update_trigger PGNSP PGUID 12 1 0 0 f f f t f v 0 0 2279 "" _null_ _null_ _null_ _null_ flatfile_update_trigger _null_ _null_ _null_ ));
|
|
||||||
DESCR("update flat-file copy of a shared catalog");
|
|
||||||
|
|
||||||
/* Oracle Compatibility Related Functions - By Edmund Mergl <E.Mergl@bawue.de> */
|
/* Oracle Compatibility Related Functions - By Edmund Mergl <E.Mergl@bawue.de> */
|
||||||
DATA(insert OID = 868 ( strpos PGNSP PGUID 12 1 0 0 f f f t f i 2 0 23 "25 25" _null_ _null_ _null_ _null_ textpos _null_ _null_ _null_ ));
|
DATA(insert OID = 868 ( strpos PGNSP PGUID 12 1 0 0 f f f t f i 2 0 23 "25 25" _null_ _null_ _null_ _null_ textpos _null_ _null_ _null_ ));
|
||||||
DESCR("find position of substring");
|
DESCR("find position of substring");
|
||||||
|
|
|
@ -1,35 +0,0 @@
|
||||||
/*-------------------------------------------------------------------------
|
|
||||||
*
|
|
||||||
* flatfiles.h
|
|
||||||
* Routines for maintaining "flat file" images of the shared catalogs.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* $PostgreSQL: pgsql/src/include/utils/flatfiles.h,v 1.6 2005/10/15 02:49:46 momjian Exp $
|
|
||||||
*
|
|
||||||
*-------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
#ifndef FLATFILES_H
|
|
||||||
#define FLATFILES_H
|
|
||||||
|
|
||||||
#include "fmgr.h"
|
|
||||||
|
|
||||||
extern void database_file_update_needed(void);
|
|
||||||
extern void auth_file_update_needed(void);
|
|
||||||
|
|
||||||
extern char *database_getflatfilename(void);
|
|
||||||
extern char *auth_getflatfilename(void);
|
|
||||||
|
|
||||||
extern void BuildFlatFiles(bool database_only);
|
|
||||||
|
|
||||||
extern void AtPrepare_UpdateFlatFiles(void);
|
|
||||||
extern void AtEOXact_UpdateFlatFiles(bool isCommit);
|
|
||||||
extern void AtEOSubXact_UpdateFlatFiles(bool isCommit,
|
|
||||||
SubTransactionId mySubid,
|
|
||||||
SubTransactionId parentSubid);
|
|
||||||
|
|
||||||
extern Datum flatfile_update_trigger(PG_FUNCTION_ARGS);
|
|
||||||
|
|
||||||
extern void flatfile_twophase_postcommit(TransactionId xid, uint16 info,
|
|
||||||
void *recdata, uint32 len);
|
|
||||||
|
|
||||||
#endif /* FLATFILES_H */
|
|
Loading…
Reference in New Issue