postinit.c

来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 662 行 · 第 1/2 页

C
662
字号
/*------------------------------------------------------------------------- * * postinit.c *	  postgres initialization utilities * * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.180.2.1 2008/09/11 14:01:35 alvherre Exp $ * * *------------------------------------------------------------------------- */#include "postgres.h"#include <fcntl.h>#include <unistd.h>#include "access/heapam.h"#include "access/xact.h"#include "catalog/catalog.h"#include "catalog/namespace.h"#include "catalog/pg_authid.h"#include "catalog/pg_database.h"#include "catalog/pg_tablespace.h"#include "libpq/hba.h"#include "mb/pg_wchar.h"#include "miscadmin.h"#include "pgstat.h"#include "postmaster/autovacuum.h"#include "postmaster/postmaster.h"#include "storage/backendid.h"#include "storage/fd.h"#include "storage/ipc.h"#include "storage/proc.h"#include "storage/procarray.h"#include "storage/sinval.h"#include "storage/smgr.h"#include "utils/acl.h"#include "utils/flatfiles.h"#include "utils/guc.h"#include "utils/plancache.h"#include "utils/portal.h"#include "utils/relcache.h"#include "utils/tqual.h"#include "utils/syscache.h"static bool FindMyDatabase(const char *name, Oid *db_id, Oid *db_tablespace);static bool FindMyDatabaseByOid(Oid dbid, char *dbname, Oid *db_tablespace);static void CheckMyDatabase(const char *name, bool am_superuser);static void InitCommunication(void);static void ShutdownPostgres(int code, Datum arg);static bool ThereIsAtLeastOneRole(void);/*** InitPostgres support ***//* * FindMyDatabase -- get the critical info needed to locate my database * * Find the named database in pg_database, return its database OID and the * OID of its default tablespace.  Return TRUE if found, FALSE if not. * * Since we are not yet up and running as a backend, we cannot look directly * at pg_database (we can't obtain locks nor participate in transactions). * So to get the info we need before starting up, we must look at the "flat * file" copy of pg_database that is helpfully maintained by flatfiles.c. * This is subject to various race conditions, so after we have the * transaction infrastructure started, we have to recheck the information; * see InitPostgres. */static boolFindMyDatabase(const char *name, Oid *db_id, Oid *db_tablespace){	bool		result = false;	char	   *filename;	FILE	   *db_file;	char		thisname[NAMEDATALEN];	TransactionId db_frozenxid;	filename = database_getflatfilename();	db_file = AllocateFile(filename, "r");	if (db_file == NULL)		ereport(FATAL,				(errcode_for_file_access(),				 errmsg("could not open file \"%s\": %m", filename)));	while (read_pg_database_line(db_file, thisname, db_id,								 db_tablespace, &db_frozenxid))	{		if (strcmp(thisname, name) == 0)		{			result = true;			break;		}	}	FreeFile(db_file);	pfree(filename);	return result;}/* * FindMyDatabaseByOid * * As above, but the actual database Id is known.  Return its name and the * tablespace OID.	Return TRUE if found, FALSE if not.  The same restrictions * as FindMyDatabase apply. */static boolFindMyDatabaseByOid(Oid dbid, char *dbname, Oid *db_tablespace){	bool		result = false;	char	   *filename;	FILE	   *db_file;	Oid			db_id;	char		thisname[NAMEDATALEN];	TransactionId db_frozenxid;	filename = database_getflatfilename();	db_file = AllocateFile(filename, "r");	if (db_file == NULL)		ereport(FATAL,				(errcode_for_file_access(),				 errmsg("could not open file \"%s\": %m", filename)));	while (read_pg_database_line(db_file, thisname, &db_id,								 db_tablespace, &db_frozenxid))	{		if (dbid == db_id)		{			result = true;			strlcpy(dbname, thisname, NAMEDATALEN);			break;		}	}	FreeFile(db_file);	pfree(filename);	return result;}/* * CheckMyDatabase -- fetch information from the pg_database entry for our DB */static voidCheckMyDatabase(const char *name, bool am_superuser){	HeapTuple	tup;	Form_pg_database dbform;	/* Fetch our real pg_database row */	tup = SearchSysCache(DATABASEOID,						 ObjectIdGetDatum(MyDatabaseId),						 0, 0, 0);	if (!HeapTupleIsValid(tup))		elog(ERROR, "cache lookup failed for database %u", MyDatabaseId);	dbform = (Form_pg_database) GETSTRUCT(tup);	/* This recheck is strictly paranoia */	if (strcmp(name, NameStr(dbform->datname)) != 0)		ereport(FATAL,				(errcode(ERRCODE_UNDEFINED_DATABASE),				 errmsg("database \"%s\" has disappeared from pg_database",						name),				 errdetail("Database OID %u now seems to belong to \"%s\".",						   MyDatabaseId, NameStr(dbform->datname))));	/*	 * Check permissions to connect to the database.	 *	 * These checks are not enforced when in standalone mode, so that there is	 * a way to recover from disabling all access to all databases, for	 * example "UPDATE pg_database SET datallowconn = false;".	 *	 * We do not enforce them for the autovacuum worker processes either.	 */	if (IsUnderPostmaster && !IsAutoVacuumWorkerProcess())	{		/*		 * Check that the database is currently allowing connections.		 */		if (!dbform->datallowconn)			ereport(FATAL,					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),			 errmsg("database \"%s\" is not currently accepting connections",					name)));		/*		 * Check privilege to connect to the database.	(The am_superuser test		 * is redundant, but since we have the flag, might as well check it		 * and save a few cycles.)		 */		if (!am_superuser &&			pg_database_aclcheck(MyDatabaseId, GetUserId(),								 ACL_CONNECT) != ACLCHECK_OK)			ereport(FATAL,					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),					 errmsg("permission denied for database \"%s\"", name),					 errdetail("User does not have CONNECT privilege.")));		/*		 * Check connection limit for this database.		 *		 * There is a race condition here --- we create our PGPROC before		 * checking for other PGPROCs.	If two backends did this at about the		 * same time, they might both think they were over the limit, while		 * ideally one should succeed and one fail.  Getting that to work		 * exactly seems more trouble than it is worth, however; instead we		 * just document that the connection limit is approximate.		 */		if (dbform->datconnlimit >= 0 &&			!am_superuser &&			CountDBBackends(MyDatabaseId) > dbform->datconnlimit)			ereport(FATAL,					(errcode(ERRCODE_TOO_MANY_CONNECTIONS),					 errmsg("too many connections for database \"%s\"",							name)));	}	/*	 * OK, we're golden.  Next to-do item is to save the encoding info out of	 * the pg_database tuple.	 */	SetDatabaseEncoding(dbform->encoding);	/* Record it as a GUC internal option, too */	SetConfigOption("server_encoding", GetDatabaseEncodingName(),					PGC_INTERNAL, PGC_S_OVERRIDE);	/* If we have no other source of client_encoding, use server encoding */	SetConfigOption("client_encoding", GetDatabaseEncodingName(),					PGC_BACKEND, PGC_S_DEFAULT);	/*	 * Lastly, set up any database-specific configuration variables.	 */	if (IsUnderPostmaster)	{		Datum		datum;		bool		isnull;		datum = SysCacheGetAttr(DATABASEOID, tup, Anum_pg_database_datconfig,								&isnull);		if (!isnull)		{			ArrayType  *a = DatumGetArrayTypeP(datum);			/*			 * We process all the options at SUSET level.  We assume that the			 * right to insert an option into pg_database was checked when it			 * was inserted.			 */			ProcessGUCArray(a, PGC_SUSET, PGC_S_DATABASE, GUC_ACTION_SET);		}	}	ReleaseSysCache(tup);}/* -------------------------------- *		InitCommunication * *		This routine initializes stuff needed for ipc, locking, etc. *		it should be called something more informative. * -------------------------------- */static voidInitCommunication(void){	/*	 * initialize shared memory and semaphores appropriately.	 */	if (!IsUnderPostmaster)		/* postmaster already did this */	{		/*		 * We're running a postgres bootstrap process or a standalone backend.		 * Create private "shmem" and semaphores.		 */		CreateSharedMemoryAndSemaphores(true, 0);	}}/* * Early initialization of a backend (either standalone or under postmaster). * This happens even before InitPostgres. * * If you're wondering why this is separate from InitPostgres at all: * the critical distinction is that this stuff has to happen before we can * run XLOG-related initialization, which is done before InitPostgres --- in * fact, for cases such as checkpoint creation processes, InitPostgres may * never be done at all. */voidBaseInit(void){	/*	 * Attach to shared memory and semaphores, and initialize our	 * input/output/debugging file descriptors.	 */	InitCommunication();	DebugFileOpen();	/* Do local initialization of file, storage and buffer managers */	InitFileAccess();	smgrinit();	InitBufferPoolAccess();}/* -------------------------------- * InitPostgres *		Initialize POSTGRES. * * The database can be specified by name, using the in_dbname parameter, or by * OID, using the dboid parameter.	In the latter case, the computed database * name is passed out to the caller as a palloc'ed string in out_dbname. * * In bootstrap mode no parameters are used. * * The return value indicates whether the userID is a superuser.  (That * can only be tested inside a transaction, so we want to do it during * the startup transaction rather than doing a separate one in postgres.c.)

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?