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 + -
显示快捷键?