mirror of
https://github.com/postgres/postgres.git
synced 2025-11-12 05:01:15 +03:00
Several changes here, not very related but touching some of the same files.
* Buffer refcount cleanup (per my "progress report" to pghackers, 9/22). * Add links to backend PROC structs to sinval's array of per-backend info, and use these links for routines that need to check the state of all backends (rather than the slow, complicated search of the ShmemIndex hashtable that was used before). Add databaseOID to PROC structs. * Use this to implement an interlock that prevents DESTROY DATABASE of a database containing running backends. (It's a little tricky to prevent a concurrently-starting backend from getting in there, since the new backend is not able to lock anything at the time it tries to look up its database in pg_database. My solution is to recheck that the DB is OK at the end of InitPostgres. It may not be a 100% solution, but it's a lot better than no interlock at all...) * In ALTER TABLE RENAME, flush buffers for the relation before doing the rename of the physical files, to ensure we don't get failures later from mdblindwrt(). * Update TRUNCATE patch so that it actually compiles against current sources :-(. You should do "make clean all" after pulling these changes.
This commit is contained in:
@@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.48 1999/07/17 20:18:08 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.49 1999/09/24 00:24:58 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* InitPostgres() is the function called from PostgresMain
|
||||
@@ -36,6 +36,7 @@
|
||||
|
||||
#include "access/heapam.h"
|
||||
#include "catalog/catname.h"
|
||||
#include "catalog/pg_database.h"
|
||||
#include "libpq/libpq.h"
|
||||
#include "miscadmin.h"
|
||||
#include "storage/backendid.h"
|
||||
@@ -54,13 +55,12 @@
|
||||
|
||||
static void VerifySystemDatabase(void);
|
||||
static void VerifyMyDatabase(void);
|
||||
static void ReverifyMyDatabase(char *name);
|
||||
static void InitCommunication(void);
|
||||
static void InitMyDatabaseInfo(char *name);
|
||||
static void InitStdio(void);
|
||||
static void InitUserid(void);
|
||||
|
||||
extern char *ExpandDatabasePath(char *name);
|
||||
extern void GetRawDatabaseInfo(char *name, int4 *owner, Oid *db_id, char *path, int *encoding);
|
||||
|
||||
static IPCKey PostgresIpcKey;
|
||||
|
||||
@@ -98,13 +98,11 @@ static IPCKey PostgresIpcKey;
|
||||
static void
|
||||
InitMyDatabaseInfo(char *name)
|
||||
{
|
||||
int4 owner;
|
||||
char *path,
|
||||
myPath[MAXPGPATH + 1];
|
||||
int encoding;
|
||||
|
||||
SetDatabaseName(name);
|
||||
GetRawDatabaseInfo(name, &owner, &MyDatabaseId, myPath, &encoding);
|
||||
GetRawDatabaseInfo(name, &MyDatabaseId, myPath);
|
||||
|
||||
if (!OidIsValid(MyDatabaseId))
|
||||
elog(FATAL,
|
||||
@@ -114,11 +112,6 @@ InitMyDatabaseInfo(char *name)
|
||||
|
||||
path = ExpandDatabasePath(myPath);
|
||||
SetDatabasePath(path);
|
||||
#ifdef MULTIBYTE
|
||||
SetDatabaseEncoding(encoding);
|
||||
#endif
|
||||
|
||||
return;
|
||||
} /* InitMyDatabaseInfo() */
|
||||
|
||||
|
||||
@@ -249,6 +242,86 @@ VerifyMyDatabase()
|
||||
/* Above does not return */
|
||||
} /* VerifyMyDatabase() */
|
||||
|
||||
/* --------------------------------
|
||||
* ReverifyMyDatabase
|
||||
*
|
||||
* Since we are forced to fetch the database OID out of pg_database without
|
||||
* benefit of locking or transaction ID checking (see utils/misc/database.c),
|
||||
* we might have gotten a wrong answer. Or, we might have attached to a
|
||||
* database that's in process of being destroyed by destroydb(). This
|
||||
* routine is called after we have all the locking and other infrastructure
|
||||
* running --- now we can check that we are really attached to a valid
|
||||
* database.
|
||||
*
|
||||
* In reality, if destroydb() is running in parallel with our startup,
|
||||
* it's pretty likely that we will have failed before now, due to being
|
||||
* unable to read some of the system tables within the doomed database.
|
||||
* This routine just exists to make *sure* we have not started up in an
|
||||
* invalid database. If we quit now, we should have managed to avoid
|
||||
* creating any serious problems.
|
||||
*
|
||||
* This is also a handy place to fetch the database encoding info out
|
||||
* of pg_database, if we are in MULTIBYTE mode.
|
||||
* --------------------------------
|
||||
*/
|
||||
static void
|
||||
ReverifyMyDatabase(char *name)
|
||||
{
|
||||
Relation pgdbrel;
|
||||
HeapScanDesc pgdbscan;
|
||||
ScanKeyData key;
|
||||
HeapTuple tup;
|
||||
|
||||
/*
|
||||
* Because we grab AccessShareLock here, we can be sure that
|
||||
* destroydb is not running in parallel with us (any more).
|
||||
*/
|
||||
pgdbrel = heap_openr(DatabaseRelationName, AccessShareLock);
|
||||
|
||||
ScanKeyEntryInitialize(&key, 0, Anum_pg_database_datname,
|
||||
F_NAMEEQ, NameGetDatum(name));
|
||||
|
||||
pgdbscan = heap_beginscan(pgdbrel, 0, SnapshotNow, 1, &key);
|
||||
|
||||
tup = heap_getnext(pgdbscan, 0);
|
||||
if (!HeapTupleIsValid(tup) ||
|
||||
tup->t_data->t_oid != MyDatabaseId)
|
||||
{
|
||||
/* OOPS */
|
||||
heap_close(pgdbrel, AccessShareLock);
|
||||
/*
|
||||
* The only real problem I could have created is to load dirty
|
||||
* buffers for the dead database into shared buffer cache;
|
||||
* if I did, some other backend will eventually try to write
|
||||
* them and die in mdblindwrt. Flush any such pages to forestall
|
||||
* trouble.
|
||||
*/
|
||||
DropBuffers(MyDatabaseId);
|
||||
/* Now I can commit hara-kiri with a clear conscience... */
|
||||
elog(FATAL, "Database '%s', OID %u, has disappeared from pg_database",
|
||||
name, MyDatabaseId);
|
||||
}
|
||||
|
||||
/*
|
||||
* OK, we're golden. Only other to-do item is to save the MULTIBYTE
|
||||
* encoding info out of the pg_database tuple. Note we also set the
|
||||
* "template encoding", which is the default encoding for any
|
||||
* CREATE DATABASE commands executed in this backend; essentially,
|
||||
* you get the same encoding of the database you connected to as
|
||||
* the default. (This replaces code that unreliably grabbed
|
||||
* template1's encoding out of pg_database. We could do an extra
|
||||
* scan to find template1's tuple, but for 99.99% of all backend
|
||||
* startups it'd be wasted cycles --- and the 'createdb' script
|
||||
* connects to template1 anyway, so there's no difference.)
|
||||
*/
|
||||
#ifdef MULTIBYTE
|
||||
SetDatabaseEncoding(((Form_pg_database) GETSTRUCT(tup))->encoding);
|
||||
SetTemplateEncoding(((Form_pg_database) GETSTRUCT(tup))->encoding);
|
||||
#endif
|
||||
|
||||
heap_endscan(pgdbscan);
|
||||
heap_close(pgdbrel, AccessShareLock);
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* InitUserid
|
||||
@@ -402,17 +475,11 @@ InitStdio()
|
||||
* Be very careful with the order of calls in the InitPostgres function.
|
||||
* --------------------------------
|
||||
*/
|
||||
bool PostgresIsInitialized = false;
|
||||
extern int NBuffers;
|
||||
|
||||
/*
|
||||
* this global is used by wei for testing his code, but must be declared
|
||||
* here rather than in postgres.c so that it's defined for cinterface.a
|
||||
* applications.
|
||||
*/
|
||||
bool PostgresIsInitialized = false;
|
||||
|
||||
/*int testFlag = 0;*/
|
||||
int lockingOff = 0;
|
||||
int lockingOff = 0; /* backend -L switch */
|
||||
|
||||
/*
|
||||
*/
|
||||
@@ -530,22 +597,22 @@ InitPostgres(char *name) /* database name */
|
||||
LockDisable(false);
|
||||
|
||||
/* ----------------
|
||||
* anyone knows what this does? something having to do with
|
||||
* system catalog cache invalidation in the case of multiple
|
||||
* backends, I think -cim 10/3/90
|
||||
* Sets up MyBackendId a unique backend identifier.
|
||||
* ----------------
|
||||
*/
|
||||
InitSharedInvalidationState();
|
||||
|
||||
/* ----------------
|
||||
* Set up a per backend process in shared memory. Must be done after
|
||||
* InitSharedInvalidationState() as it relies on MyBackendId being
|
||||
* initialized already. XXX -mer 11 Aug 1991
|
||||
* Set up my per-backend PROC struct in shared memory.
|
||||
* ----------------
|
||||
*/
|
||||
InitProcess(PostgresIpcKey);
|
||||
|
||||
/* ----------------
|
||||
* Initialize my entry in the shared-invalidation manager's
|
||||
* array of per-backend data. (Formerly this came before
|
||||
* InitProcess, but now it must happen after, because it uses
|
||||
* MyProc.) Once I have done this, I am visible to other backends!
|
||||
*
|
||||
* Sets up MyBackendId, a unique backend identifier.
|
||||
* ----------------
|
||||
*/
|
||||
InitSharedInvalidationState();
|
||||
|
||||
if (MyBackendId > MAXBACKENDS || MyBackendId <= 0)
|
||||
{
|
||||
elog(FATAL, "cinit2: bad backend id %d (%d)",
|
||||
@@ -592,7 +659,6 @@ InitPostgres(char *name) /* database name */
|
||||
* ----------------
|
||||
*/
|
||||
PostgresIsInitialized = true;
|
||||
/* on_shmem_exit(DestroyLocalRelList, (caddr_t) NULL); */
|
||||
|
||||
/* ----------------
|
||||
* Done with "InitPostgres", now change to NormalProcessing unless
|
||||
@@ -601,7 +667,14 @@ InitPostgres(char *name) /* database name */
|
||||
*/
|
||||
if (!bootstrap)
|
||||
SetProcessingMode(NormalProcessing);
|
||||
/* if (testFlag || lockingOff) */
|
||||
if (lockingOff)
|
||||
LockDisable(true);
|
||||
|
||||
/*
|
||||
* Unless we are bootstrapping, double-check that InitMyDatabaseInfo()
|
||||
* got a correct result. We can't do this until essentially all the
|
||||
* infrastructure is up, so just do it at the end.
|
||||
*/
|
||||
if (!bootstrap)
|
||||
ReverifyMyDatabase(name);
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* database.c
|
||||
* miscellanious initialization support stuff
|
||||
* miscellaneous initialization support stuff
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/misc/Attic/database.c,v 1.29 1999/09/18 19:08:07 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/misc/Attic/database.c,v 1.30 1999/09/24 00:25:04 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -21,10 +21,6 @@
|
||||
#include "miscadmin.h"
|
||||
#include "utils/syscache.h"
|
||||
|
||||
#ifdef MULTIBYTE
|
||||
#include "mb/pg_wchar.h"
|
||||
#endif
|
||||
|
||||
#ifdef NOT_USED
|
||||
/* GetDatabaseInfo()
|
||||
* Pull database information from pg_database.
|
||||
@@ -153,24 +149,13 @@ ExpandDatabasePath(char *dbpath)
|
||||
* cache. To get around this problem, this code opens and scans the
|
||||
* pg_database relation by hand.
|
||||
*
|
||||
* This algorithm relies on the fact that first attribute in the
|
||||
* pg_database relation schema is the database name. It also knows
|
||||
* about the internal format of tuples on disk and the length of
|
||||
* the datname attribute. It knows the location of the pg_database
|
||||
* file.
|
||||
* Actually, the code looks as though it is using the pg_database
|
||||
* tuple definition to locate the database name, so the above statement
|
||||
* seems to be no longer correct. - thomas 1997-11-01
|
||||
*
|
||||
* This code is called from InitPostgres(), before we chdir() to the
|
||||
* local database directory and before we open any relations.
|
||||
* Used to be called after the chdir(), but we now want to confirm
|
||||
* the location of the target database using pg_database info.
|
||||
* - thomas 1997-11-01
|
||||
* This code knows way more than it should about the layout of
|
||||
* tuples on disk, but there seems to be no help for that.
|
||||
* We're pulling ourselves up by the bootstraps here...
|
||||
* --------------------------------
|
||||
*/
|
||||
void
|
||||
GetRawDatabaseInfo(char *name, int4 *owner, Oid *db_id, char *path, int *encoding)
|
||||
GetRawDatabaseInfo(char *name, Oid *db_id, char *path)
|
||||
{
|
||||
int dbfd;
|
||||
int fileflags;
|
||||
@@ -238,48 +223,38 @@ GetRawDatabaseInfo(char *name, int4 *owner, Oid *db_id, char *path, int *encodin
|
||||
* skip this tuple. XXX warning, will robinson: violation of
|
||||
* transaction semantics happens right here. we should check
|
||||
* to be sure that the xact that deleted this tuple actually
|
||||
* committed. only way to do this at init time is to paw over
|
||||
* the log relation by hand, too. let's be optimistic.
|
||||
* committed. Only way to do that at init time is to paw over
|
||||
* the log relation by hand, too. Instead we take the
|
||||
* conservative assumption that if someone tried to delete it,
|
||||
* it's gone. The other side of the coin is that we might
|
||||
* accept a tuple that was stored and never committed. All in
|
||||
* all, this code is pretty shaky. We will cross-check our
|
||||
* result in ReverifyMyDatabase() in postinit.c.
|
||||
*
|
||||
* XXX This is an evil type cast. tup->t_xmax is char[5] while
|
||||
* TransactionId is struct * { char data[5] }. It works but
|
||||
* if data is ever moved and no longer the first field this
|
||||
* will be broken!! -mer 11 Nov 1991.
|
||||
* NOTE: if a bogus tuple in pg_database prevents connection
|
||||
* to a valid database, a fix is to connect to another database
|
||||
* and do "select * from pg_database". That should cause
|
||||
* committed and dead tuples to be marked with correct states.
|
||||
*
|
||||
* XXX wouldn't it be better to let new backends read the
|
||||
* database OID from a flat file, handled the same way
|
||||
* we handle the password relation?
|
||||
*/
|
||||
if (TransactionIdIsValid((TransactionId) tup.t_data->t_xmax))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Okay, see if this is the one we want. XXX 1 july 91: mao
|
||||
* and mer discover that tuples now squash t_bits. Why is
|
||||
* this?
|
||||
*
|
||||
* 24 july 92: mer realizes that the t_bits field is only used
|
||||
* in the event of null values. If no fields are null we
|
||||
* reduce the header size by doing the squash. t_hoff tells
|
||||
* you exactly how big the header actually is. use the PC
|
||||
* means of getting at sys cat attrs.
|
||||
* Okay, see if this is the one we want.
|
||||
*/
|
||||
tup_db = (Form_pg_database) GETSTRUCT(&tup);
|
||||
#ifdef MULTIBYTE
|
||||
|
||||
/*
|
||||
* get encoding from template database. This is the "default
|
||||
* for default" for create database command.
|
||||
*/
|
||||
if (strcmp("template1", tup_db->datname.data) == 0)
|
||||
SetTemplateEncoding(tup_db->encoding);
|
||||
#endif
|
||||
if (strcmp(name, tup_db->datname.data) == 0)
|
||||
{
|
||||
/* Found it; extract the OID and the database path. */
|
||||
*db_id = tup.t_data->t_oid;
|
||||
strncpy(path, VARDATA(&(tup_db->datpath)),
|
||||
(VARSIZE(&(tup_db->datpath)) - VARHDRSZ));
|
||||
*(path + VARSIZE(&(tup_db->datpath)) - VARHDRSZ) = '\0';
|
||||
#ifdef MULTIBYTE
|
||||
*encoding = tup_db->encoding;
|
||||
#endif
|
||||
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user