📄 postinit.c
字号:
/*------------------------------------------------------------------------- * * postinit.c * postgres initialization utilities * * Portions Copyright (c) 1996-2005, 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.158.2.1 2005/11/22 18:23:24 momjian Exp $ * * *------------------------------------------------------------------------- */#include "postgres.h"#include <fcntl.h>#include <sys/file.h>#include <math.h>#include <unistd.h>#include "access/genam.h"#include "access/heapam.h"#include "catalog/catalog.h"#include "catalog/indexing.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 "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/fmgroids.h"#include "utils/guc.h"#include "utils/portal.h"#include "utils/relcache.h"#include "utils/syscache.h"#include "pgstat.h"static bool FindMyDatabase(const char *name, Oid *db_id, Oid *db_tablespace);static void ReverifyMyDatabase(const char *name);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 ReverifyMyDatabase. */static boolFindMyDatabase(const char *name, Oid *db_id, Oid *db_tablespace){ bool result = false; char *filename; FILE *db_file; char thisname[NAMEDATALEN]; TransactionId dummyxid; 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, &dummyxid, &dummyxid)) { if (strcmp(thisname, name) == 0) { result = true; break; } } FreeFile(db_file); pfree(filename); return result;}/* * ReverifyMyDatabase -- recheck info obtained by FindMyDatabase * * Since FindMyDatabase cannot lock pg_database, the information it read * could be stale; for example we might have attached to a database that's in * process of being destroyed by dropdb(). 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 dropdb() 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. * * To avoid having to read pg_database more times than necessary * during session startup, this place is also fitting to set up any * database-specific configuration variables. */static voidReverifyMyDatabase(const char *name){ Relation pgdbrel; SysScanDesc pgdbscan; ScanKeyData key; HeapTuple tup; Form_pg_database dbform; /* * Because we grab RowShareLock here, we can be sure that dropdb() is not * running in parallel with us (any more). */ pgdbrel = heap_open(DatabaseRelationId, RowShareLock); ScanKeyInit(&key, Anum_pg_database_datname, BTEqualStrategyNumber, F_NAMEEQ, NameGetDatum(name)); pgdbscan = systable_beginscan(pgdbrel, DatabaseNameIndexId, true, SnapshotNow, 1, &key); tup = systable_getnext(pgdbscan); if (!HeapTupleIsValid(tup) || HeapTupleGetOid(tup) != MyDatabaseId) { /* OOPS */ heap_close(pgdbrel, RowShareLock); /* * 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... */ ereport(FATAL, (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("database \"%s\", OID %u, has disappeared from pg_database", name, MyDatabaseId))); } dbform = (Form_pg_database) GETSTRUCT(tup); /* * These next 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 process either. */ if (IsUnderPostmaster && !IsAutoVacuumProcess()) { /* * 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 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 && !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 = heap_getattr(tup, Anum_pg_database_datconfig, RelationGetDescr(pgdbrel), &isnull); if (!isnull) { ArrayType *a = DatumGetArrayTypeP(datum); ProcessGUCArray(a, PGC_S_DATABASE); } } systable_endscan(pgdbscan); heap_close(pgdbrel, RowShareLock);}/* -------------------------------- * 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();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -