postinit.c

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

C
662
字号
 * * As of PostgreSQL 8.2, we expect InitProcess() was already called, so we * already have a PGPROC struct ... but it's not filled in yet. * * Note: *		Be very careful with the order of calls in the InitPostgres function. * -------------------------------- */boolInitPostgres(const char *in_dbname, Oid dboid, const char *username,			 char **out_dbname){	bool		bootstrap = IsBootstrapProcessingMode();	bool		autovacuum = IsAutoVacuumWorkerProcess();	bool		am_superuser;	char	   *fullpath;	char		dbname[NAMEDATALEN];	/*	 * Set up the global variables holding database id and path.  But note we	 * won't actually try to touch the database just yet.	 *	 * We take a shortcut in the bootstrap case, otherwise we have to look up	 * the db name in pg_database.	 */	if (bootstrap)	{		MyDatabaseId = TemplateDbOid;		MyDatabaseTableSpace = DEFAULTTABLESPACE_OID;	}	else	{		/*		 * Find tablespace of the database we're about to open. Since we're		 * not yet up and running we have to use one of the hackish		 * FindMyDatabase variants, which look in the flat-file copy of		 * pg_database.		 *		 * If the in_dbname param is NULL, lookup database by OID.		 */		if (in_dbname == NULL)		{			if (!FindMyDatabaseByOid(dboid, dbname, &MyDatabaseTableSpace))				ereport(FATAL,						(errcode(ERRCODE_UNDEFINED_DATABASE),						 errmsg("database %u does not exist", dboid)));			MyDatabaseId = dboid;			/* pass the database name to the caller */			*out_dbname = pstrdup(dbname);		}		else		{			if (!FindMyDatabase(in_dbname, &MyDatabaseId, &MyDatabaseTableSpace))				ereport(FATAL,						(errcode(ERRCODE_UNDEFINED_DATABASE),						 errmsg("database \"%s\" does not exist",								in_dbname)));			/* our database name is gotten from the caller */			strlcpy(dbname, in_dbname, NAMEDATALEN);		}	}	fullpath = GetDatabasePath(MyDatabaseId, MyDatabaseTableSpace);	SetDatabasePath(fullpath);	/*	 * Finish filling in the PGPROC struct, and add it to the ProcArray. (We	 * need to know MyDatabaseId before we can do this, since it's entered	 * into the PGPROC struct.)	 *	 * Once I have done this, I am visible to other backends!	 */	InitProcessPhase2();	/*	 * Initialize my entry in the shared-invalidation manager's array of	 * per-backend data.	 *	 * Sets up MyBackendId, a unique backend identifier.	 */	MyBackendId = InvalidBackendId;	InitBackendSharedInvalidationState();	if (MyBackendId > MaxBackends || MyBackendId <= 0)		elog(FATAL, "bad backend id: %d", MyBackendId);	/*	 * bufmgr needs another initialization call too	 */	InitBufferPoolBackend();	/*	 * Initialize local process's access to XLOG.  In bootstrap case we may	 * skip this since StartupXLOG() was run instead.	 */	if (!bootstrap)		InitXLOGAccess();	/*	 * Initialize the relation cache and the system catalog caches.  Note that	 * no catalog access happens here; we only set up the hashtable structure.	 * We must do this before starting a transaction because transaction abort	 * would try to touch these hashtables.	 */	RelationCacheInitialize();	InitCatalogCache();	InitPlanCache();	/* Initialize portal manager */	EnablePortalManager();	/* Initialize stats collection --- must happen before first xact */	if (!bootstrap)		pgstat_initialize();	/*	 * Set up process-exit callback to do pre-shutdown cleanup.  This has to	 * be after we've initialized all the low-level modules like the buffer	 * manager, because during shutdown this has to run before the low-level	 * modules start to close down.  On the other hand, we want it in place	 * before we begin our first transaction --- if we fail during the	 * initialization transaction, as is entirely possible, we need the	 * AbortTransaction call to clean up.	 */	on_shmem_exit(ShutdownPostgres, 0);	/*	 * Start a new transaction here before first access to db, and get a	 * snapshot.  We don't have a use for the snapshot itself, but we're	 * interested in the secondary effect that it sets RecentGlobalXmin.	 */	if (!bootstrap)	{		StartTransactionCommand();		(void) GetTransactionSnapshot();	}	/*	 * Now that we have a transaction, we can take locks.  Take a writer's	 * lock on the database we are trying to connect to.  If there is a	 * concurrently running DROP DATABASE on that database, this will block us	 * until it finishes (and has updated the flat file copy of pg_database).	 *	 * Note that the lock is not held long, only until the end of this startup	 * transaction.  This is OK since we are already advertising our use of	 * the database in the PGPROC array; anyone trying a DROP DATABASE after	 * this point will see us there.	 *	 * Note: use of RowExclusiveLock here is reasonable because we envision	 * our session as being a concurrent writer of the database.  If we had a	 * way of declaring a session as being guaranteed-read-only, we could use	 * AccessShareLock for such sessions and thereby not conflict against	 * CREATE DATABASE.	 */	if (!bootstrap)		LockSharedObject(DatabaseRelationId, MyDatabaseId, 0,						 RowExclusiveLock);	/*	 * Recheck the flat file copy of pg_database to make sure the target	 * database hasn't gone away.  If there was a concurrent DROP DATABASE,	 * this ensures we will die cleanly without creating a mess.	 */	if (!bootstrap)	{		Oid			dbid2;		Oid			tsid2;		if (!FindMyDatabase(dbname, &dbid2, &tsid2) ||			dbid2 != MyDatabaseId || tsid2 != MyDatabaseTableSpace)			ereport(FATAL,					(errcode(ERRCODE_UNDEFINED_DATABASE),					 errmsg("database \"%s\" does not exist",							dbname),			   errdetail("It seems to have just been dropped or renamed.")));	}	/*	 * Now we should be able to access the database directory safely. Verify	 * it's there and looks reasonable.	 */	if (!bootstrap)	{		if (access(fullpath, F_OK) == -1)		{			if (errno == ENOENT)				ereport(FATAL,						(errcode(ERRCODE_UNDEFINED_DATABASE),						 errmsg("database \"%s\" does not exist",								dbname),					errdetail("The database subdirectory \"%s\" is missing.",							  fullpath)));			else				ereport(FATAL,						(errcode_for_file_access(),						 errmsg("could not access directory \"%s\": %m",								fullpath)));		}		ValidatePgVersion(fullpath);	}	/*	 * It's now possible to do real access to the system catalogs.	 *	 * Load relcache entries for the system catalogs.  This must create at	 * least the minimum set of "nailed-in" cache entries.	 */	RelationCacheInitializePhase2();	/*	 * Figure out our postgres user id, and see if we are a superuser.	 *	 * In standalone mode and in the autovacuum process, we use a fixed id,	 * otherwise we figure it out from the authenticated user name.	 */	if (bootstrap || autovacuum)	{		InitializeSessionUserIdStandalone();		am_superuser = true;	}	else if (!IsUnderPostmaster)	{		InitializeSessionUserIdStandalone();		am_superuser = true;		if (!ThereIsAtLeastOneRole())			ereport(WARNING,					(errcode(ERRCODE_UNDEFINED_OBJECT),					 errmsg("no roles are defined in this database system"),					 errhint("You should immediately run CREATE USER \"%s\" CREATEUSER;.",							 username)));	}	else	{		/* normal multiuser case */		InitializeSessionUserId(username);		am_superuser = superuser();	}	/* set up ACL framework (so CheckMyDatabase can check permissions) */	initialize_acl();	/*	 * Read the real pg_database row for our database, check permissions and	 * set up database-specific GUC settings.  We can't do this until all the	 * database-access infrastructure is up.  (Also, it wants to know if the	 * user is a superuser, so the above stuff has to happen first.)	 */	if (!bootstrap)		CheckMyDatabase(dbname, am_superuser);	/*	 * Check a normal user hasn't connected to a superuser reserved slot.	 */	if (!am_superuser &&		ReservedBackends > 0 &&		!HaveNFreeProcs(ReservedBackends))		ereport(FATAL,				(errcode(ERRCODE_TOO_MANY_CONNECTIONS),				 errmsg("connection limit exceeded for non-superusers")));	/*	 * Initialize various default states that can't be set up until we've	 * selected the active user and gotten the right GUC settings.	 */	/* set default namespace search path */	InitializeSearchPath();	/* initialize client encoding */	InitializeClientEncoding();	/* report this backend in the PgBackendStatus array */	if (!bootstrap)		pgstat_bestart();	/* close the transaction we started above */	if (!bootstrap)		CommitTransactionCommand();	return am_superuser;}/* * Backend-shutdown callback.  Do cleanup that we want to be sure happens * before all the supporting modules begin to nail their doors shut via * their own callbacks. * * User-level cleanup, such as temp-relation removal and UNLISTEN, happens * via separate callbacks that execute before this one.  We don't combine the * callbacks because we still want this one to happen if the user-level * cleanup fails. */static voidShutdownPostgres(int code, Datum arg){	/* Make sure we've killed any active transaction */	AbortOutOfAnyTransaction();	/*	 * User locks are not released by transaction end, so be sure to release	 * them explicitly.	 */	LockReleaseAll(USER_LOCKMETHOD, true);}/* * Returns true if at least one role is defined in this database cluster. */static boolThereIsAtLeastOneRole(void){	Relation	pg_authid_rel;	HeapScanDesc scan;	bool		result;	pg_authid_rel = heap_open(AuthIdRelationId, AccessShareLock);	scan = heap_beginscan(pg_authid_rel, SnapshotNow, 0, NULL);	result = (heap_getnext(scan, ForwardScanDirection) != NULL);	heap_endscan(scan);	heap_close(pg_authid_rel, AccessShareLock);	return result;}

⌨️ 快捷键说明

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