head 1.30; access werner shectman; symbols; locks; strict; comment @ * @; 1.30 date 92.01.29.16.49.32; author postgres; state Exp; branches; next 1.29; 1.29 date 91.11.12.20.20.29; author mer; state Exp; branches; next ; desc @Initial Ported Version @ 1.30 log @Removed a bootstrap test. @ text @/* ---------------------------------------------------------------- * FILE * postinit.c * * DESCRIPTION * postgres initialization utilities * * INTERFACE ROUTINES * InitPostgres() * * NOTES * InitializePostgres() is the function called from PostgresMain * which does all non-trival initialization, mainly by calling * all the other initialization functions. InitializePostgres() * is only used within the "postgres" backend and so that routine * is in tcop/postgres.c InitPostgres() is needed in cinterface.a * because things like the bootstrap backend program need it. Hence * you find that in this file... * * If you feel the need to add more initialization code, it should be * done in InitializePostgres() or someplace lower. Do not start * putting stuff in PostgresMain - if you do then someone * will have to clean it up later, and it's not going to be me! * -cim 10/3/90 * * IDENTIFICATION * $Header: /general/TFA/unclassified/src/utils/postgres-v3r1/src/utils/init/RCS/postinit.c,v 1.29 1991/11/12 20:20:29 mer Exp postgres $ * ---------------------------------------------------------------- */ #include #include #include #include #include #include #include "tmp/postgres.h" #include "machine.h" /* for BLCKSZ, for InitMyDatabaseId() */ #include "access/heapam.h" #include "access/tqual.h" #include "storage/bufpage.h" /* for page layout, for InitMyDatabaseId() */ #include "storage/sinval.h" #include "storage/sinvaladt.h" #include "storage/lmgr.h" #include "support/master.h" #include "tmp/miscadmin.h" #include "tmp/portal.h" /* for EnablePortalManager, etc. */ #include "utils/exc.h" /* for EnableExceptionHandling, etc. */ #include "utils/fmgr.h" /* for EnableDynamicFunctionManager, etc. */ #include "utils/log.h" #include "utils/mcxt.h" /* for EnableMemoryContext, etc. */ #include "catalog/catname.h" #include "tmp/miscadmin.h" /* ---------------- * global variables & stuff * XXX clean this up! -cim 10/5/90 * ---------------- */ extern bool override; extern int Quiet; IPCKey PostgresIpcKey; /* * XXX PostgresPath and PostgresDatabase belong somewhere else. */ String PostgresPath = NULL; String PostgresDatabase = NULL; extern int Debugfile, Ttyfile, Dblog, Slog; extern int Portfd, Packfd, Pipefd; extern BackendId MyBackendId; extern BackendTag MyBackendTag; extern NameData MyDatabaseNameData; extern Name MyDatabaseName; extern bool MyDatabaseIdIsInitialized; extern ObjectId MyDatabaseId; extern bool TransactionInitWasProcessed; /* extern struct bcommon Ident; No longer needed */ extern int Debug_file, Err_file, Noversion; extern int on_exitpg(); extern void BufferManagerFlush(); #ifndef private #ifndef EBUG #define private static #else /* !defined(EBUG) */ #define private #endif /* !defined(EBUG) */ #endif /* !defined(private) */ /* ---------------------------------------------------------------- * InitPostgres support * ---------------------------------------------------------------- */ /* -------------------------------- * InitMyDatabaseId() -- Find and record the OID of the database we are * to open. * * The database's oid forms half of the unique key for the system * caches and lock tables. We therefore want it initialized before * we open any relations, since opening relations puts things in the * cache. To get around this problem, this code opens and scans the * pg_database relation by hand. * * This algorithm relies on the fact that first attribute in the * pg_database relation schema is the database name. It also knows * about the internal format of tuples on disk and the length of * the datname attribute. It knows the location of the pg_database * file. * * This code is called from InitDatabase(), after we chdir() to the * database directory but before we open any relations. * -------------------------------- */ void InitMyDatabaseId() { int dbfd; int nbytes; int max, i; HeapTuple tup; char *tup_db; Page pg; PageHeader ph; /* ---------------- * If we're unable to open pg_database, we're not running in the * data/base/dbname directory. This happens only when we're * creating the first database. In that case, just use * InvalidObjectId as the dbid, since we're not using shared memory. * ---------------- */ if ((dbfd = open("../../pg_database", O_RDONLY, 0666)) < 0) { LockDisable(true); return; } /* ---------------- * read and examine every page in pg_database * * Raw I/O! Read those tuples the hard way! Yow! * * Why don't we use the access methods or move this code * someplace else? This is really pg_database schema dependent * code. Perhaps it should go in lib/catalog/pg_database? * -cim 10/3/90 * * mao replies 4 apr 91: yeah, maybe this should be moved to * lib/catalog. however, we CANNOT use the access methods since * those use the buffer cache, which uses the relation cache, which * requires that the dbid be set, which is what we're trying to do * here. * ---------------- */ pg = (Page) palloc(BLCKSZ); ph = (PageHeader) pg; while ((nbytes = read(dbfd, pg, BLCKSZ)) == BLCKSZ) { max = PageGetMaxOffsetIndex(pg); /* look at each tuple on the page */ for (i = 0; i <= max; i++) { int offset; /* if it's a freed tuple, ignore it */ if (!(ph->pd_linp[i].lp_flags & LP_USED)) continue; /* get a pointer to the tuple itself */ offset = (int) ph->pd_linp[i].lp_off; tup = (HeapTuple) (((char *) pg) + offset); /* * if the tuple has been deleted (the database was destroyed), * skip this tuple. XXX warning, will robinson: violation of * transaction semantics happens right here. we should check * to be sure that the xact that deleted this tuple actually * committed. only way to do this at init time is to paw over * the log relation by hand, too. let's be optimistic. * * XXX This is an evil type cast. tup->t_xmax is char[5] while * TransactionId is struct * { char data[5] }. It works but * if data is ever moved and no longer the first field this * will be broken!! -mer 11 Nov 1991. */ if (TransactionIdIsValid((TransactionId)tup->t_xmax)) continue; /* * Okay, see if this is the one we want. * XXX 1 july 91: mao and mer discover that tuples now squash * t_bits. Why is this? */ tup_db = ((char *) tup) + sizeof (*tup) - sizeof(tup->t_bits); /* note: MyDatabaseName set by call to SetDatabaseName() */ if (strncmp(MyDatabaseName, tup_db, 16) == 0) { MyDatabaseId = tup->t_oid; goto done; } } } done: (void) close(dbfd); pfree(pg); /* ---------------- * don't know why this is here -- historical artifact. --mao * ---------------- */ if (ObjectIdIsValid(MyDatabaseId)) LockDisable(false); else LockDisable(true); } /* ---------------- * DoChdirAndInitDatabaseNameAndPath * * this just chdir's to the proper data/base directory * XXX clean this up more. * * XXX The following code is an incorrect of the semantics * XXX described in the header file. Handling of defaults * XXX should happen here, too. * ---------------- */ void DoChdirAndInitDatabaseNameAndPath(name, path) String name; /* name of database */ String path; /* full path to database */ { /* ---------------- * sanity check (database may not change once set) * ---------------- */ AssertState(!StringIsValid(GetDatabasePath())); AssertState(!StringIsValid(GetDatabaseName())); /* ---------------- * check the path * ---------------- */ if (StringIsValid(path)) SetDatabasePath(path); else elog(FATAL, "DoChdirAndInitDatabaseNameAndPath: path:%s is not valid", path); /* ---------------- * check the name * ---------------- */ if (StringIsValid(name)) SetDatabaseName(name); else elog(FATAL, "DoChdirAndInitDatabaseNameAndPath: name:%s is not valid", name); /* ---------------- * change to the directory, or die trying. * ---------------- */ if (chdir(path) < 0) elog(FATAL, "DoChdirAndInitDatabaseNameAndPath: chdir(\"%s\"): %m", path); } /* -------------------------------- * InitUserid * * initializes crap associated with the user id. * -------------------------------- */ void InitUserid() { setuid(geteuid()); SetUserId(); } /* -------------------------------- * InitCommunication * * This routine initializes stuff needed for ipc, locking, etc. * it should be called something more informative. * * Note: * This does not set MyBackendId. MyBackendTag is set, however. * -------------------------------- */ void InitCommunication() { String getenv(); /* XXX style */ String postid; String postport; IPCKey key; /* ---------------- * try and get the backend tag from POSTID * ---------------- */ MyBackendId = -1; postid = getenv("POSTID"); if (!PointerIsValid(postid)) { MyBackendTag = -1; } else { MyBackendTag = atoi(postid); Assert(MyBackendTag >= 0); } /* ---------------- * try and get the ipc key from POSTPORT * ---------------- */ postport = getenv("POSTPORT"); if (PointerIsValid(postport)) { SystemPortAddress address = atoi(postport); if (address == 0) elog(FATAL, "InitCommunication: invalid POSTPORT"); if (MyBackendTag == -1) elog(FATAL, "InitCommunication: missing POSTID"); key = SystemPortAddressCreateIPCKey(address); /* * Enable this if you are trying to force the backend to run as if it is * running under the postmaster. * * This goto forces Postgres to attach to shared memory instead of using * malloc'ed memory (which is the normal behavior if run directly). * * To enable emulation, run the following shell commands (in addition * to enabling this goto) * * % setenv POSTID 1 * % setenv POSTPORT 4321 * % postmaster & * % kill -9 %1 * * Upon doing this, Postmaster will have allocated the shared memory resources * that Postgres will attach to if you enable EMULATE_UNDER_POSTMASTER. * * This comment may well age with time - it is current as of 8 January 1990 * * Greg */ #ifdef EMULATE_UNDER_POSTMASTER goto forcesharedmemory; #endif } else if (IsUnderPostmaster) { elog(FATAL, "InitCommunication: under postmaster and POSTPORT not set"); } else { /* ---------------- * assume we're running a postgres backend by itself with * no front end or postmaster. * ---------------- */ if (MyBackendTag == -1) { MyBackendTag = 1; } key = PrivateIPCKey; } /* ---------------- * initialize shared memory and semaphores appropriately. * ---------------- */ #ifdef EMULATE_UNDER_POSTMASTER forcesharedmemory: #endif PostgresIpcKey = key; AttachSharedMemoryAndSemaphores(key); } /* -------------------------------- * InitStdio * * this routine consists of a bunch of code fragments * that used to be randomly scattered through cinit(). * they all seem to do stuff associated with io. * -------------------------------- */ void InitStdio() { /* ---------------- * this appears to be a funky variable used with the IN and OUT * macros for controlling the error message indent level. * ---------------- */ ElogDebugIndentLevel = 0; /* ---------------- * old socket initialization crud starts here * ---------------- */ Ttyfile = 0; Debugfile = Debug_file = DebugFileOpen(); if (IsUnderPostmaster) { struct dpacket pack; /* ---------------- * why the hell are we doing this here??? -cim * ---------------- */ if (!ValidPgVersion(".") || !ValidPgVersion("../..")) { extern char *DBName; elog(NOTICE, "InitStdio: !ValidPgVersion"); if (strcmp(DBName, "template1")) elog(FATAL, "Did you run createdb on %s yet??", DBName); else elog(FATAL, "Did you run initdb yet??"); } Slog = SYSLOG_FD; /* Packfd = 5; Packfd not used see below */ Dblog = DBLOG_FD; Pipefd = 7; /* * Already done after postgres command line args processing * * Portfd = 4; * pq_init(Portfd); */ /* --------------------------- * It looks like Packfd was used to allow comm. between the postmaster * and the backend, since this never really happens we don't really need * it.... -mer 2/20/91 * --------------------------- * read(Packfd, (char *)&pack, sizeof(pack)); * bcopy(pack.data, (char *)&Ident, sizeof(Ident)); */ } #ifdef GO_SLOW if (!isatty(fileno(stdout)) && !isatty(fileno(stderr))) { setbuf(stdout, (char *)NULL); setbuf(stderr, (char *)NULL); } #endif GO_SLOW Dblog = dup(Debugfile); Err_file = ErrorFileOpen(); } /* -------------------------------- * InitPostgres * * Note: * Be very careful with the order of calls in the InitPostgres function. * -------------------------------- */ static bool PostgresIsInitialized = false; extern int NBuffers; /* * this global is used by wei for testing his code, but must be declared * here rather than in postgres.c so that it's defined for cinterface.a * applications. */ int testFlag = 0; int lockingOff = 0; /* */ void InitPostgres(name) String name; /* database name */ { bool bootstrap; /* true if BootstrapProcessing */ extern DestroyLocalRelList(); /* ---------------- * see if we're running in BootstrapProcessing mode * ---------------- */ bootstrap = IsBootstrapProcessingMode(); /* ---------------- * turn on the exception handler. Note: we cannot use elog, Assert, * AssertState, etc. until after exception handling is on. * ---------------- */ EnableExceptionHandling(true); /* ---------------- * A stupid check to make sure we don't call this more than once. * But things like ReinitPostgres() get around this by just diddling * the PostgresIsInitialized flag. * ---------------- */ AssertState(!PostgresIsInitialized); /* ---------------- * EnableTrace is poorly understood by the current postgres * implementation people. Since none of us know how it really * is intended to function, we keep it turned off for now. * Turning it on will cause a core dump in all the non-sequent * ports. Actually it may fail there too. Who knows. -cim 10/3/90 * ---------------- */ EnableTrace(false); /* ---------------- * Memory system initialization. * (we may call palloc after EnableMemoryContext()) * * Note EnableMemoryContext() must happen before EnablePortalManager(). * ---------------- */ EnableMemoryContext(true); /* initializes the "top context" */ EnablePortalManager(true); /* memory for portal/transaction stuff */ /* ---------------- * initialize the backend local portal stack used by * internal PQ function calls. see src/lib/libpq/be-dumpdata.c * This is different from the "portal manager" so this goes here. * -cim 2/12/91 * ---------------- */ be_portalinit(); /* ---------------- * set ourselves to the proper user id and figure out our postgres * user id. If we ever add security so that we check for valid * postgres users, we might do it here. * ---------------- */ InitUserid(); /* ---------------- * attach to shared memory and semaphores, and initialize our * input/output/debugging file descriptors. * ---------------- */ InitCommunication(); InitStdio(); if (!TransactionFlushEnabled()) on_exitpg(BufferManagerFlush, (caddr_t) 0); /* ---------------- * check for valid "meta gunk" (??? -cim 10/5/90) and change to * database directory. * * Note: DatabaseName, MyDatabaseName, and DatabasePath are all * initialized with DatabaseMetaGunkIsConsistent(), strncpy() and * DoChdirAndInitDatabase() below! XXX clean this crap up! * -cim 10/5/90 * ---------------- */ { static char myPath[MAXPGPATH]; /* DatabasePath points here! */ static char myName[17]; /* DatabaseName points here! */ /* ---------------- * DatabaseMetaGunkIsConsistent fills in myPath, but what about * when bootstrap or Noversion is true?? -cim 10/5/90 * ---------------- */ myPath[0] = '\0'; #ifndef sgi if (! bootstrap) #endif if (! DatabaseMetaGunkIsConsistent(name, myPath)) if (! Noversion) elog(FATAL, "InitPostgres: ! DatabaseMetaGunkIsConsistent"); (void) strncpy(myName, name, sizeof(myName)); /* ---------------- * ok, we've figured out myName and myPath, now save these * and chdir to myPath. * ---------------- */ DoChdirAndInitDatabaseNameAndPath(myName, myPath); } /* ******************************** * code after this point assumes we are in the proper directory! * ******************************** */ /* ---------------- * initialize the database id used for system caches and lock tables * ---------------- */ InitMyDatabaseId(); smgrinit(); /* ---------------- * initialize the transaction system and the relation descriptor * cache. Note we have to make certain the lock manager is off while * we do this. * ---------------- */ AmiTransactionOverride(IsBootstrapProcessingMode()); LockDisable(true); RelationInitialize(); /* pre-allocated reldescs created here */ InitializeTransactionSystem(); /* pg_log,etc init/crash recovery here */ LockDisable(false); /* ---------------- * anyone knows what this does? something having to do with * system catalog cache invalidation in the case of multiple * backends, I think -cim 10/3/90 * Sets up MyBackendId a unique backend identifier. * ---------------- */ InitSharedInvalidationState(); /* ---------------- * Set up a per backend process in shared memory. Must be done after * InitSharedInvalidationState() as it relies on MyBackendId being * initialized already. XXX -mer 11 Aug 1991 * ---------------- */ InitProcess(PostgresIpcKey); if (MyBackendId > MaxBackendId || MyBackendId <= 0) { elog(FATAL, "cinit2: bad backend id %d (%d)", MyBackendTag, MyBackendId); } /* ---------------- * initialize the access methods and set the heap-randomization * behaviour (if POSTGROWS is set then we disable the usual * random-search for a free page when we do an insertion). * ---------------- */ initam(); InitRandom(); /* XXX move this to initam() */ /* ---------------- * initialize all the system catalog caches. * ---------------- */ zerocaches(); InitCatalogCache(); /* ---------------- * ok, all done, now let's make sure we don't do it again. * ---------------- */ PostgresIsInitialized = true; on_exitpg(DestroyLocalRelList, NULL); /* ---------------- * Done with "InitPostgres", now change to NormalProcessing unless * we're in BootstrapProcessing mode. * ---------------- */ if (!bootstrap) SetProcessingMode(NormalProcessing); if (testFlag || lockingOff) LockDisable(true); } /* -------------------------------- * ReinitPostgres * * It is not clear how this routine is supposed to work, or under * what circumstances it should be called. But hirohama wrote it * for some reason so it's still here. -cim 10/3/90 * -------------------------------- */ void ReinitPostgres() { /* assumes exception handling initialized at least once before */ AssertState(PostgresIsInitialized); /* reset all modules */ EnablePortalManager(false); EnableMemoryContext(false); EnableExceptionHandling(false); EnableTrace(false); /* now reinitialize */ PostgresIsInitialized = false; /* does it matter where this goes? */ InitPostgres(NULL); } /* ---------------------------------------------------------------- * traps to catch calls to obsolete routines * ---------------------------------------------------------------- */ /* ---------------- * cinit * ---------------- */ bool cinit() { fprintf(stderr, "cinit called! eliminate this!!\n"); AbortPostgres(); } /* ---------------- * cinit2 * ---------------- */ bool cinit2() { fprintf(stderr, "cinit2 called! eliminate this!!\n"); AbortPostgres(); } @ 1.29 log @checked in with -k by werner at 1992/01/09 17:03:51 @ text @d27 1 a27 1 * $Header: RCS/postinit.c,v 1.29 91/11/12 20:20:29 mer Exp $ d600 1 a600 1 d602 1 @