📄 bootstrap.c
字号:
/*------------------------------------------------------------------------- * * bootstrap.c * routines to support running postgres in 'bootstrap' mode * bootstrap mode is used to create the initial template database * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION * $PostgreSQL: pgsql/src/backend/bootstrap/bootstrap.c,v 1.208.2.1 2005/11/22 18:23:05 momjian Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include <unistd.h>#include <signal.h>#ifdef HAVE_GETOPT_H#include <getopt.h>#endif#define BOOTSTRAP_INCLUDE /* mask out stuff in tcop/tcopprot.h */#include "access/genam.h"#include "access/heapam.h"#include "access/xlog.h"#include "bootstrap/bootstrap.h"#include "catalog/index.h"#include "catalog/pg_type.h"#include "executor/executor.h"#include "libpq/pqsignal.h"#include "miscadmin.h"#include "nodes/makefuncs.h"#include "postmaster/bgwriter.h"#include "storage/freespace.h"#include "storage/ipc.h"#include "storage/pg_shmem.h"#include "storage/proc.h"#include "tcop/tcopprot.h"#include "utils/builtins.h"#include "utils/flatfiles.h"#include "utils/fmgroids.h"#include "utils/guc.h"#include "utils/lsyscache.h"#include "utils/memutils.h"#include "utils/ps_status.h"#include "utils/relcache.h"extern int optind;extern char *optarg;#define ALLOC(t, c) ((t *) calloc((unsigned)(c), sizeof(t)))extern int Int_yyparse(void);static void usage(void);static void bootstrap_signals(void);static hashnode *AddStr(char *str, int strlength, int mderef);static Form_pg_attribute AllocateAttribute(void);static int CompHash(char *str, int len);static hashnode *FindStr(char *str, int length, hashnode *mderef);static Oid gettype(char *type);static void cleanup(void);/* ---------------- * global variables * ---------------- */Relation boot_reldesc; /* current relation descriptor *//* * In the lexical analyzer, we need to get the reference number quickly from * the string, and the string from the reference number. Thus we have * as our data structure a hash table, where the hashing key taken from * the particular string. The hash table is chained. One of the fields * of the hash table node is an index into the array of character pointers. * The unique index number that every string is assigned is simply the * position of its string pointer in the array of string pointers. */#define STRTABLESIZE 10000#define HASHTABLESIZE 503/* Hash function numbers */#define NUM 23#define NUMSQR 529#define NUMCUBE 12167char *strtable[STRTABLESIZE];hashnode *hashtable[HASHTABLESIZE];static int strtable_end = -1; /* Tells us last occupied string space *//*- * Basic information associated with each type. This is used before * pg_type is created. * * XXX several of these input/output functions do catalog scans * (e.g., F_REGPROCIN scans pg_proc). this obviously creates some * order dependencies in the catalog creation process. */struct typinfo{ char name[NAMEDATALEN]; Oid oid; Oid elem; int16 len; bool byval; char align; char storage; Oid inproc; Oid outproc;};static const struct typinfo TypInfo[] = { {"bool", BOOLOID, 0, 1, true, 'c', 'p', F_BOOLIN, F_BOOLOUT}, {"bytea", BYTEAOID, 0, -1, false, 'i', 'x', F_BYTEAIN, F_BYTEAOUT}, {"char", CHAROID, 0, 1, true, 'c', 'p', F_CHARIN, F_CHAROUT}, {"name", NAMEOID, CHAROID, NAMEDATALEN, false, 'i', 'p', F_NAMEIN, F_NAMEOUT}, {"int2", INT2OID, 0, 2, true, 's', 'p', F_INT2IN, F_INT2OUT}, {"int4", INT4OID, 0, 4, true, 'i', 'p', F_INT4IN, F_INT4OUT}, {"regproc", REGPROCOID, 0, 4, true, 'i', 'p', F_REGPROCIN, F_REGPROCOUT}, {"regclass", REGCLASSOID, 0, 4, true, 'i', 'p', F_REGCLASSIN, F_REGCLASSOUT}, {"regtype", REGTYPEOID, 0, 4, true, 'i', 'p', F_REGTYPEIN, F_REGTYPEOUT}, {"text", TEXTOID, 0, -1, false, 'i', 'x', F_TEXTIN, F_TEXTOUT}, {"oid", OIDOID, 0, 4, true, 'i', 'p', F_OIDIN, F_OIDOUT}, {"tid", TIDOID, 0, 6, false, 's', 'p', F_TIDIN, F_TIDOUT}, {"xid", XIDOID, 0, 4, true, 'i', 'p', F_XIDIN, F_XIDOUT}, {"cid", CIDOID, 0, 4, true, 'i', 'p', F_CIDIN, F_CIDOUT}, {"int2vector", INT2VECTOROID, INT2OID, -1, false, 'i', 'p', F_INT2VECTORIN, F_INT2VECTOROUT}, {"oidvector", OIDVECTOROID, OIDOID, -1, false, 'i', 'p', F_OIDVECTORIN, F_OIDVECTOROUT}, {"_int4", INT4ARRAYOID, INT4OID, -1, false, 'i', 'x', F_ARRAY_IN, F_ARRAY_OUT}, {"_text", 1009, TEXTOID, -1, false, 'i', 'x', F_ARRAY_IN, F_ARRAY_OUT}, {"_oid", 1028, OIDOID, -1, false, 'i', 'x', F_ARRAY_IN, F_ARRAY_OUT}, {"_char", 1002, CHAROID, -1, false, 'i', 'x', F_ARRAY_IN, F_ARRAY_OUT}, {"_aclitem", 1034, ACLITEMOID, -1, false, 'i', 'x', F_ARRAY_IN, F_ARRAY_OUT}};static const int n_types = sizeof(TypInfo) / sizeof(struct typinfo);struct typmap{ /* a hack */ Oid am_oid; FormData_pg_type am_typ;};static struct typmap **Typ = NULL;static struct typmap *Ap = NULL;static int Warnings = 0;static char Blanks[MAXATTR];Form_pg_attribute attrtypes[MAXATTR]; /* points to attribute info */static Datum values[MAXATTR]; /* corresponding attribute values */int numattr; /* number of attributes for cur. rel */static MemoryContext nogc = NULL; /* special no-gc mem context *//* * At bootstrap time, we first declare all the indices to be built, and * then build them. The IndexList structure stores enough information * to allow us to build the indices after they've been declared. */typedef struct _IndexList{ Oid il_heap; Oid il_ind; IndexInfo *il_info; struct _IndexList *il_next;} IndexList;static IndexList *ILHead = NULL;/* * The main entry point for running the backend in bootstrap mode * * The bootstrap mode is used to initialize the template database. * The bootstrap backend doesn't speak SQL, but instead expects * commands in a special bootstrap language. * * For historical reasons, BootstrapMain is also used as the control * routine for non-backend subprocesses launched by the postmaster, * such as startup and shutdown. */intBootstrapMain(int argc, char *argv[]){ char *progname = argv[0]; int i; char *dbname; int flag; int xlogop = BS_XLOG_NOP; char *userDoption = NULL; /* * initialize globals */ MyProcPid = getpid(); /* * Fire up essential subsystems: error and memory management * * If we are running under the postmaster, this is done already. */ if (!IsUnderPostmaster) MemoryContextInit(); /* Compute paths, if we didn't inherit them from postmaster */ if (my_exec_path[0] == '\0') { if (find_my_exec(progname, my_exec_path) < 0) elog(FATAL, "%s: could not locate my own executable path", progname); } /* * process command arguments */ /* Set defaults, to be overriden by explicit options below */ dbname = NULL; if (!IsUnderPostmaster) InitializeGUCOptions(); /* Ignore the initial -boot argument, if present */ if (argc > 1 && strcmp(argv[1], "-boot") == 0) { argv++; argc--; } while ((flag = getopt(argc, argv, "B:c:d:D:Fo:p:x:-:")) != -1) { switch (flag) { case 'D': userDoption = optarg; break; case 'd': { /* Turn on debugging for the bootstrap process. */ char *debugstr = palloc(strlen("debug") + strlen(optarg) + 1); sprintf(debugstr, "debug%s", optarg); SetConfigOption("log_min_messages", debugstr, PGC_POSTMASTER, PGC_S_ARGV); SetConfigOption("client_min_messages", debugstr, PGC_POSTMASTER, PGC_S_ARGV); pfree(debugstr); } break; case 'F': SetConfigOption("fsync", "false", PGC_POSTMASTER, PGC_S_ARGV); break; case 'o': StrNCpy(OutputFileName, optarg, MAXPGPATH); break; case 'x': xlogop = atoi(optarg); break; case 'p': dbname = strdup(optarg); break; case 'B': SetConfigOption("shared_buffers", optarg, PGC_POSTMASTER, PGC_S_ARGV); break; case 'c': case '-': { char *name, *value; ParseLongOption(optarg, &name, &value); if (!value) { if (flag == '-') ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("--%s requires a value", optarg))); else ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("-c %s requires a value", optarg))); } SetConfigOption(name, value, PGC_POSTMASTER, PGC_S_ARGV); free(name); if (value) free(value); break; } default: usage(); break; } } if (!dbname && argc - optind == 1) { dbname = argv[optind]; optind++; } if (!dbname || argc != optind) usage(); /* * Identify myself via ps */ if (IsUnderPostmaster) { const char *statmsg; switch (xlogop) { case BS_XLOG_STARTUP: statmsg = "startup process"; break; case BS_XLOG_BGWRITER: statmsg = "writer process"; break; default: statmsg = "??? process"; break; } init_ps_display(statmsg, "", ""); set_ps_display(""); } /* Acquire configuration parameters, unless inherited from postmaster */ if (!IsUnderPostmaster) { if (!SelectConfigFiles(userDoption, progname)) proc_exit(1); /* If timezone is not set, determine what the OS uses */ pg_timezone_initialize(); } /* Validate we have been given a reasonable-looking DataDir */ Assert(DataDir); ValidatePgVersion(DataDir); /* Change into DataDir (if under postmaster, should be done already) */ if (!IsUnderPostmaster) ChangeToDataDir(); /* If standalone, create lockfile for data directory */ if (!IsUnderPostmaster) CreateDataDirLockFile(false); SetProcessingMode(BootstrapProcessing); IgnoreSystemIndexes(true); BaseInit(); /* * We aren't going to do the full InitPostgres pushups, but there are a * couple of things that need to get lit up even in a dummy process. */ if (IsUnderPostmaster) { /* set up proc.c to get use of LWLocks */ switch (xlogop) { case BS_XLOG_BGWRITER: InitDummyProcess(DUMMY_PROC_BGWRITER); break; default: InitDummyProcess(DUMMY_PROC_DEFAULT); break; } /* finish setting up bufmgr.c */ InitBufferPoolBackend(); } /* * XLOG operations */ SetProcessingMode(NormalProcessing); switch (xlogop) { case BS_XLOG_NOP: bootstrap_signals(); break; case BS_XLOG_BOOTSTRAP: bootstrap_signals(); BootStrapXLOG(); StartupXLOG(); break; case BS_XLOG_STARTUP: bootstrap_signals(); StartupXLOG(); LoadFreeSpaceMap(); BuildFlatFiles(false); proc_exit(0); /* startup done */ case BS_XLOG_BGWRITER: /* don't set signals, bgwriter has its own agenda */ InitXLOGAccess(); BackgroundWriterMain(); proc_exit(1); /* should never return */ default: elog(PANIC, "unrecognized XLOG op: %d", xlogop); proc_exit(1); } SetProcessingMode(BootstrapProcessing); /* * backend initialization */ (void) InitPostgres(dbname, NULL); /* * In NOP mode, all we really want to do is create shared memory and * semaphores (just to prove we can do it with the current GUC settings). * So, quit now. */ if (xlogop == BS_XLOG_NOP) proc_exit(0); /* Initialize stuff for bootstrap-file processing */ for (i = 0; i < MAXATTR; i++) { attrtypes[i] = NULL; Blanks[i] = ' '; } for (i = 0; i < STRTABLESIZE; ++i) strtable[i] = NULL; for (i = 0; i < HASHTABLESIZE; ++i) hashtable[i] = NULL; /* * Process bootstrap input. * * the sed script boot.sed renamed yyparse to Int_yyparse for the * bootstrap parser to avoid conflicts with the normal SQL parser */ Int_yyparse(); /* Perform a checkpoint to ensure everything's down to disk */ SetProcessingMode(NormalProcessing); CreateCheckPoint(true, true); SetProcessingMode(BootstrapProcessing); /* Clean up and exit */ StartTransactionCommand(); cleanup(); /* not reached, here to make compiler happy */ return 0;}/* ---------------------------------------------------------------- * misc functions * ---------------------------------------------------------------- *//* usage: * usage help for the bootstrap backend */static voidusage(void){ write_stderr("Usage:\n" " postgres -boot [OPTION]... DBNAME\n" " -c NAME=VALUE set run-time parameter\n" " -d 1-5 debug level\n" " -D datadir data directory\n" " -F turn off fsync\n" " -o file send debug output to file\n" " -x num internal use\n"); proc_exit(1);}/* * Set up signal handling for a bootstrap process */static voidbootstrap_signals(void){ if (IsUnderPostmaster) { /* * Properly accept or ignore signals the postmaster might send us */ pqsignal(SIGHUP, SIG_IGN); pqsignal(SIGINT, SIG_IGN); /* ignore query-cancel */ pqsignal(SIGTERM, die); pqsignal(SIGQUIT, quickdie); pqsignal(SIGALRM, SIG_IGN); pqsignal(SIGPIPE, SIG_IGN); pqsignal(SIGUSR1, SIG_IGN); pqsignal(SIGUSR2, SIG_IGN); /* * Reset some signals that are accepted by postmaster but not here */ pqsignal(SIGCHLD, SIG_DFL); pqsignal(SIGTTIN, SIG_DFL); pqsignal(SIGTTOU, SIG_DFL); pqsignal(SIGCONT, SIG_DFL); pqsignal(SIGWINCH, SIG_DFL); /* * Unblock signals (they were blocked when the postmaster forked us) */ PG_SETMASK(&UnBlockSig); } else { /* Set up appropriately for interactive use */ pqsignal(SIGHUP, die); pqsignal(SIGINT, die); pqsignal(SIGTERM, die); pqsignal(SIGQUIT, die); }}/* ---------------- * error handling / abort routines * ---------------- */voiderr_out(void){ Warnings++; cleanup();}/* ---------------------------------------------------------------- * MANUAL BACKEND INTERACTIVE INTERFACE COMMANDS * ---------------------------------------------------------------- *//* ---------------- * boot_openrel * ---------------- */voidboot_openrel(char *relname){ int i; struct typmap **app; Relation rel; HeapScanDesc scan; HeapTuple tup; if (strlen(relname) >= NAMEDATALEN) relname[NAMEDATALEN - 1] = '\0'; if (Typ == NULL) { rel = heap_open(TypeRelationId, NoLock); scan = heap_beginscan(rel, SnapshotNow, 0, NULL); i = 0; while ((tup = heap_getnext(scan, ForwardScanDirection)) != NULL) ++i; heap_endscan(scan); app = Typ = ALLOC(struct typmap *, i + 1); while (i-- > 0) *app++ = ALLOC(struct typmap, 1); *app = NULL; scan = heap_beginscan(rel, SnapshotNow, 0, NULL); app = Typ; while ((tup = heap_getnext(scan, ForwardScanDirection)) != NULL) { (*app)->am_oid = HeapTupleGetOid(tup); memcpy((char *) &(*app)->am_typ, (char *) GETSTRUCT(tup), sizeof((*app)->am_typ)); app++; } heap_endscan(scan); heap_close(rel, NoLock); } if (boot_reldesc != NULL) closerel(NULL); elog(DEBUG4, "open relation %s, attrsize %d", relname, (int) ATTRIBUTE_TUPLE_SIZE); boot_reldesc = heap_openrv(makeRangeVar(NULL, relname), NoLock); numattr = boot_reldesc->rd_rel->relnatts; for (i = 0; i < numattr; i++) { if (attrtypes[i] == NULL)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -