]> granicus.if.org Git - postgresql/blob - src/backend/utils/init/postinit.c
Should finish cleaning out the machine.h includes
[postgresql] / src / backend / utils / init / postinit.c
1 /*-------------------------------------------------------------------------
2  *
3  * postinit.c--
4  *    postgres initialization utilities
5  *
6  * Copyright (c) 1994, Regents of the University of California
7  *
8  *
9  * IDENTIFICATION
10  *    $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.2 1996/08/27 22:21:34 scrappy Exp $
11  *
12  * NOTES
13  *      InitPostgres() is the function called from PostgresMain
14  *      which does all non-trival initialization, mainly by calling
15  *      all the other initialization functions.  InitPostgres()
16  *      is only used within the "postgres" backend and so that routine
17  *      is in tcop/postgres.c  InitPostgres() is needed in cinterface.a
18  *      because things like the bootstrap backend program need it. Hence
19  *      you find that in this file...
20  *
21  *      If you feel the need to add more initialization code, it should be
22  *      done in InitPostgres() or someplace lower.  Do not start
23  *      putting stuff in PostgresMain - if you do then someone
24  *      will have to clean it up later, and it's not going to be me!
25  *      -cim 10/3/90
26  *
27  *-------------------------------------------------------------------------
28  */
29 #include <fcntl.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <sys/file.h>
33 #include <sys/types.h>
34 #include <math.h>
35
36 #include "postgres.h"
37
38 #include "access/heapam.h"
39 #include "access/xact.h"
40 #include "storage/bufmgr.h"
41 #include "access/transam.h"     /* XXX dependency problem */
42 #include "utils/tqual.h"
43 #include "utils/syscache.h"
44 #include "storage/bufpage.h"    /* for page layout, for InitMyDatabaseId() */
45 #include "storage/sinval.h"
46 #include "storage/sinvaladt.h"
47 #include "storage/lmgr.h"
48
49 #include "miscadmin.h"         /* for global decls */
50 #include "utils/portal.h"       /* for EnablePortalManager, etc. */
51
52 #include "utils/exc.h"          /* for EnableExceptionHandling, etc. */
53 #include "fmgr.h"               /* for EnableDynamicFunctionManager, etc. */
54 #include "utils/elog.h"
55 #include "utils/palloc.h"
56 #include "utils/mcxt.h"         /* for EnableMemoryContext, etc. */
57
58 #include "catalog/catname.h"
59 #include "catalog/pg_database.h"
60
61 #include "port-protos.h"
62 #include "libpq/libpq-be.h"
63
64
65 static IPCKey           PostgresIpcKey;
66
67
68 #ifndef private
69 #ifndef EBUG
70 #define private static
71 #else   /* !defined(EBUG) */
72 #define private
73 #endif  /* !defined(EBUG) */
74 #endif  /* !defined(private) */
75
76 /* ----------------------------------------------------------------
77  *                      InitPostgres support
78  * ----------------------------------------------------------------
79  */
80
81 /* --------------------------------
82  *  InitMyDatabaseId() -- Find and record the OID of the database we are
83  *                        to open.
84  *
85  *      The database's oid forms half of the unique key for the system
86  *      caches and lock tables.  We therefore want it initialized before
87  *      we open any relations, since opening relations puts things in the
88  *      cache.  To get around this problem, this code opens and scans the
89  *      pg_database relation by hand.
90  *
91  *      This algorithm relies on the fact that first attribute in the
92  *      pg_database relation schema is the database name.  It also knows
93  *      about the internal format of tuples on disk and the length of
94  *      the datname attribute.  It knows the location of the pg_database
95  *      file.
96  *
97  *      This code is called from InitDatabase(), after we chdir() to the
98  *      database directory but before we open any relations.
99  * --------------------------------
100  */
101 void
102 InitMyDatabaseId()
103 {
104     int         dbfd;
105     int         fileflags;
106     int         nbytes;
107     int         max, i;
108     HeapTuple   tup;
109     Page        pg;
110     PageHeader  ph;
111     char        *dbfname;
112     Form_pg_database    tup_db;
113     
114     /*
115      *  At bootstrap time, we don't need to check the oid of the database
116      *  in use, since we're not using shared memory.  This is lucky, since
117      *  the database may not be in the tables yet.
118      */
119     
120     if (IsBootstrapProcessingMode()) {
121         LockDisable(true);
122         return;
123     }
124     
125     dbfname = (char *) palloc(strlen(DataDir) + strlen("pg_database") + 2);
126     sprintf(dbfname, "%s%cpg_database", DataDir, SEP_CHAR);
127     fileflags = O_RDONLY;
128 #ifdef WIN32
129     fileflags |= _O_BINARY;
130 #endif /* WIN32 */
131     
132     if ((dbfd = open(dbfname, O_RDONLY, 0666)) < 0)
133         elog(FATAL, "Cannot open %s", dbfname);
134     
135     pfree(dbfname);
136     
137     /* ----------------
138      *  read and examine every page in pg_database
139      *
140      *  Raw I/O! Read those tuples the hard way! Yow!
141      *
142      *  Why don't we use the access methods or move this code
143      *  someplace else?  This is really pg_database schema dependent
144      *  code.  Perhaps it should go in lib/catalog/pg_database?
145      *  -cim 10/3/90
146      *
147      *  mao replies 4 apr 91:  yeah, maybe this should be moved to
148      *  lib/catalog.  however, we CANNOT use the access methods since
149      *  those use the buffer cache, which uses the relation cache, which
150      *  requires that the dbid be set, which is what we're trying to do
151      *  here.
152      * ----------------
153      */
154     pg = (Page) palloc(BLCKSZ);
155     ph = (PageHeader) pg;
156     
157     while ((nbytes = read(dbfd, pg, BLCKSZ)) == BLCKSZ) {
158         max = PageGetMaxOffsetNumber(pg);
159         
160         /* look at each tuple on the page */
161         for (i = 0; i <= max; i++) {
162             int offset;
163             
164             /* if it's a freed tuple, ignore it */
165             if (!(ph->pd_linp[i].lp_flags & LP_USED))
166                 continue;
167             
168             /* get a pointer to the tuple itself */
169             offset = (int) ph->pd_linp[i].lp_off;
170             tup = (HeapTuple) (((char *) pg) + offset);
171             
172             /*
173              *  if the tuple has been deleted (the database was destroyed),
174              *  skip this tuple.  XXX warning, will robinson:  violation of
175              *  transaction semantics happens right here.  we should check
176              *  to be sure that the xact that deleted this tuple actually
177              *  committed.  only way to do this at init time is to paw over
178              *  the log relation by hand, too.  let's be optimistic.
179              *
180              *  XXX This is an evil type cast.  tup->t_xmax is char[5] while
181              *  TransactionId is struct * { char data[5] }.  It works but
182              *  if data is ever moved and no longer the first field this 
183              *  will be broken!! -mer 11 Nov 1991.
184              */
185             if (TransactionIdIsValid((TransactionId)tup->t_xmax))
186                 continue;
187             
188             /*
189              *  Okay, see if this is the one we want.
190              *  XXX 1 july 91:  mao and mer discover that tuples now squash
191              *                  t_bits.  Why is this?
192              *
193              *     24 july 92:  mer realizes that the t_bits field is only
194              *                  used in the event of null values.  If no
195              *                  fields are null we reduce the header size
196              *                  by doing the squash.  t_hoff tells you exactly
197              *                  how big the header actually is. use the PC
198              *                  means of getting at sys cat attrs.
199              */
200             tup_db = (Form_pg_database)GETSTRUCT(tup);
201             
202             if (strncmp(GetDatabaseName(),
203                         &(tup_db->datname.data[0]),
204                         16) == 0)
205                 {
206                     MyDatabaseId = tup->t_oid;
207                     goto done;
208                 }
209         }
210     }
211     
212  done:
213     (void) close(dbfd);
214     pfree(pg);
215     
216     if (!OidIsValid(MyDatabaseId))
217         elog(FATAL,
218              "Database %s does not exist in %s",
219              GetDatabaseName(),
220              DatabaseRelationName);
221 }
222
223 /*
224  * DoChdirAndInitDatabaseNameAndPath --
225  *      Sets current directory appropriately for given path and name.
226  *
227  * Arguments:
228  *      Path and name are invalid if it invalid as a string.
229  *      Path is "badly formated" if it is not a string containing a path
230  *      to a writable directory.
231  *      Name is "badly formated" if it contains more than 16 characters or if
232  *      it is a bad file name (e.g., it contains a '/' or an 8-bit character).
233  *
234  * Side effects:
235  *      Initially, DatabasePath and DatabaseName are invalid.  They are
236  *      set to valid strings before this function returns.
237  *
238  * Exceptions:
239  *      BadState if called more than once.
240  *      BadArg if both path and name are "badly formated" or invalid.
241  *      BadArg if path and name are both "inconsistent" and valid.
242  */
243 /* ----------------
244  *      DoChdirAndInitDatabaseNameAndPath
245  *
246  *      this just chdir's to the proper data/base directory
247  *      XXX clean this up more.
248  *
249  * XXX The following code is an incorrect of the semantics
250  * XXX described in the header file.  Handling of defaults
251  * XXX should happen here, too.
252  * ----------------
253  */
254 void
255 DoChdirAndInitDatabaseNameAndPath(char *name, /* name of database */
256                                   char *path) /* full path to database */
257 {
258     /* ----------------
259      *  check the path
260      * ----------------
261      */
262     if (path)
263         SetDatabasePath(path);
264     else
265         elog(FATAL, "DoChdirAndInitDatabaseNameAndPath: path:%s is not valid",
266              path);
267     
268     /* ----------------
269      *  check the name
270      * ----------------
271      */
272     if (name)
273         SetDatabaseName(name);
274     else 
275         elog(FATAL, "DoChdirAndInitDatabaseNameAndPath: name:%s is not valid",
276              name);
277     
278     /* ----------------
279      *  change to the directory, or die trying.
280      *
281      *  XXX unless the path hasn't been set because we're bootstrapping.
282      *      HP-UX doesn't like chdir("") so check for that case before
283      *      doing anything drastic.
284      * ----------------
285      */
286     if (*path && (chdir(path) < 0))
287         elog(FATAL, "DoChdirAndInitDatabaseNameAndPath: chdir(\"%s\"): %m",
288              path);
289 }
290
291 /* --------------------------------
292  *      InitUserid
293  *
294  *      initializes crap associated with the user id.
295  * --------------------------------
296  */
297 void
298 InitUserid()
299 {
300     setuid(geteuid());
301     SetUserId();
302 }
303
304 /* --------------------------------
305  *      InitCommunication
306  *
307  *      This routine initializes stuff needed for ipc, locking, etc.
308  *      it should be called something more informative.
309  *
310  * Note:
311  *      This does not set MyBackendId.  MyBackendTag is set, however.
312  * --------------------------------
313  */
314 void
315 InitCommunication()
316 {
317     char *getenv();     /* XXX style */
318     char *postid;
319     char *postport;
320     IPCKey      key;
321     
322     /* ----------------
323      *  try and get the backend tag from POSTID
324      * ----------------
325      */
326     MyBackendId = -1;
327     
328     postid = getenv("POSTID");
329     if (!PointerIsValid(postid)) {
330         MyBackendTag = -1;
331     } else {
332         MyBackendTag = atoi(postid);
333         Assert(MyBackendTag >= 0);
334     }
335     
336     /* ----------------
337      *  try and get the ipc key from POSTPORT
338      * ----------------
339      */
340     postport = getenv("POSTPORT");
341     
342     if (PointerIsValid(postport)) {
343         SystemPortAddress address = atoi(postport);
344         
345         if (address == 0)
346             elog(FATAL, "InitCommunication: invalid POSTPORT");
347         
348         if (MyBackendTag == -1)
349             elog(FATAL, "InitCommunication: missing POSTID");
350         
351         key = SystemPortAddressCreateIPCKey(address);
352         
353         /*
354          * Enable this if you are trying to force the backend to run as if it 
355          * is running under the postmaster.
356          *
357          * This goto forces Postgres to attach to shared memory instead of 
358          * using malloc'ed memory (which is the normal behavior if run
359          * directly).
360          *
361          * To enable emulation, run the following shell commands (in addition
362          * to enabling this goto)
363          *
364          *     % setenv POSTID 1
365          *     % setenv POSTPORT 4321
366          *     % postmaster &
367          *     % kill -9 %1
368          *
369          * Upon doing this, Postmaster will have allocated the shared memory 
370          * resources that Postgres will attach to if you enable
371          * EMULATE_UNDER_POSTMASTER.
372          *
373          * This comment may well age with time - it is current as of
374          * 8 January 1990
375          * 
376          * Greg
377          */
378         
379 #ifdef EMULATE_UNDER_POSTMASTER
380         
381         goto forcesharedmemory;
382         
383 #endif
384         
385     } else if (IsUnderPostmaster) {
386         elog(FATAL,
387              "InitCommunication: under postmaster and POSTPORT not set");
388     } else {
389         /* ----------------
390          *  assume we're running a postgres backend by itself with
391          *  no front end or postmaster.
392          * ----------------
393          */
394         if (MyBackendTag == -1) {
395             MyBackendTag = 1;
396         }
397         
398         key = PrivateIPCKey;
399     }
400     
401     /* ----------------
402      *  initialize shared memory and semaphores appropriately.
403      * ----------------
404      */
405 #ifdef EMULATE_UNDER_POSTMASTER
406     
407  forcesharedmemory:
408     
409 #endif
410     
411     PostgresIpcKey = key;
412     AttachSharedMemoryAndSemaphores(key);
413 }
414
415
416 /* --------------------------------
417  *      InitStdio
418  *
419  *      this routine consists of a bunch of code fragments
420  *      that used to be randomly scattered through cinit().
421  *      they all seem to do stuff associated with io.
422  * --------------------------------
423  */
424 void
425 InitStdio()
426 {
427     (void) DebugFileOpen();
428 }
429
430 /* --------------------------------
431  * InitPostgres --
432  *      Initialize POSTGRES.
433  *
434  * Note:
435  *      Be very careful with the order of calls in the InitPostgres function.
436  * --------------------------------
437  */
438 bool PostgresIsInitialized = false;
439 extern int NBuffers;
440
441 /*
442  *  this global is used by wei for testing his code, but must be declared
443  *  here rather than in postgres.c so that it's defined for cinterface.a
444  *  applications.
445  */
446
447 /*int   testFlag = 0;*/
448 int     lockingOff = 0;
449
450 /*
451  */
452 void
453 InitPostgres(char *name)        /* database name */
454 {
455     bool        bootstrap;      /* true if BootstrapProcessing */
456     
457     /* ----------------
458      *  see if we're running in BootstrapProcessing mode
459      * ----------------
460      */
461     bootstrap = IsBootstrapProcessingMode();
462     
463     /* ----------------
464      *  turn on the exception handler.  Note: we cannot use elog, Assert,
465      *  AssertState, etc. until after exception handling is on.
466      * ----------------
467      */
468     EnableExceptionHandling(true);
469     
470     /* ----------------
471      *  A stupid check to make sure we don't call this more than once.
472      *  But things like ReinitPostgres() get around this by just diddling
473      *  the PostgresIsInitialized flag.
474      * ----------------
475      */
476     AssertState(!PostgresIsInitialized);
477     
478     /* ----------------
479      *  Memory system initialization.
480      *  (we may call palloc after EnableMemoryContext())
481      *
482      *  Note EnableMemoryContext() must happen before EnablePortalManager().
483      * ----------------
484      */
485     EnableMemoryContext(true);  /* initializes the "top context" */
486     EnablePortalManager(true);  /* memory for portal/transaction stuff */
487     
488     /* ----------------
489      *  initialize the backend local portal stack used by
490      *  internal PQ function calls.  see src/lib/libpq/be-dumpdata.c
491      *  This is different from the "portal manager" so this goes here.
492      *  -cim 2/12/91
493      * ----------------
494      */    
495     be_portalinit();
496     
497     /* ----------------
498      *   attach to shared memory and semaphores, and initialize our
499      *   input/output/debugging file descriptors.
500      * ----------------
501      */
502     InitCommunication();
503     InitStdio();
504     
505     /*
506      * initialize the local buffer manager
507      */
508     InitLocalBuffer();
509
510     if (!TransactionFlushEnabled())
511         on_exitpg(FlushBufferPool, (caddr_t) NULL);
512     
513     /* ----------------
514      *  check for valid "meta gunk" (??? -cim 10/5/90) and change to
515      *  database directory.
516      *
517      *  Note:  DatabaseName, MyDatabaseName, and DatabasePath are all
518      *  initialized with DatabaseMetaGunkIsConsistent(), strncpy() and
519      *  DoChdirAndInitDatabase() below!  XXX clean this crap up!
520      *  -cim 10/5/90
521      * ----------------
522      */
523     {
524         char  myPath[MAXPGPATH] = ".";  /* DatabasePath points here! */
525         
526         /* ----------------
527          *  DatabaseMetaGunkIsConsistent fills in myPath, but what about
528          *  when bootstrap or Noversion is true?? -cim 10/5/90
529          * ----------------
530          */
531         
532         if (! bootstrap &&
533             ! DatabaseMetaGunkIsConsistent(name, myPath) &&
534             ! Noversion) {
535             elog(NOTICE, "InitPostgres: could not locate valid PG_VERSION\n");
536             elog(NOTICE, "files for %s and %s.", DataDir, name);
537             elog(FATAL,  "Have you run initdb/createdb and set PGDATA properly?");
538         }
539         
540         /* ----------------
541          *  ok, we've figured out myName and myPath, now save these
542          *  and chdir to myPath.
543          * ----------------
544          */
545         DoChdirAndInitDatabaseNameAndPath(name, myPath);
546     }
547     
548     /* ********************************
549      *  code after this point assumes we are in the proper directory!
550      * ********************************
551      */
552     
553     /* ----------------
554      *  initialize the database id used for system caches and lock tables
555      * ----------------
556      */
557     InitMyDatabaseId();
558     
559     smgrinit();
560     
561     /* ----------------
562      *  initialize the transaction system and the relation descriptor
563      *  cache.  Note we have to make certain the lock manager is off while
564      *  we do this.
565      * ----------------
566      */
567     AmiTransactionOverride(IsBootstrapProcessingMode());
568     LockDisable(true);
569     
570     /*
571      * Part of the initialization processing done here sets a read
572      * lock on pg_log.  Since locking is disabled the set doesn't have
573      * intended effect of locking out writers, but this is ok, since
574      * we only lock it to examine AMI transaction status, and this is
575      * never written after initdb is done. -mer 15 June 1992
576      */
577     RelationInitialize();          /* pre-allocated reldescs created here */
578     InitializeTransactionSystem(); /* pg_log,etc init/crash recovery here */
579     
580     LockDisable(false);
581     
582     /* ----------------
583      *  anyone knows what this does?  something having to do with
584      *  system catalog cache invalidation in the case of multiple
585      *  backends, I think -cim 10/3/90
586      *  Sets up MyBackendId a unique backend identifier.
587      * ----------------
588      */
589     InitSharedInvalidationState();
590     
591     /* ----------------
592      * Set up a per backend process in shared memory.  Must be done after
593      * InitSharedInvalidationState() as it relies on MyBackendId being
594      * initialized already.  XXX -mer 11 Aug 1991
595      * ----------------
596      */
597     InitProcess(PostgresIpcKey);
598     
599     if (MyBackendId > MaxBackendId || MyBackendId <= 0) {
600         elog(FATAL, "cinit2: bad backend id %d (%d)",
601              MyBackendTag,
602              MyBackendId);
603     }
604     
605     /* ----------------
606      *  initialize the access methods.
607      * ----------------
608      */
609     initam();
610     
611     /* ----------------
612      *  initialize all the system catalog caches.
613      * ----------------
614      */
615     zerocaches();
616     InitCatalogCache();
617     
618     /* ----------------
619      *   set ourselves to the proper user id and figure out our postgres
620      *   user id.  If we ever add security so that we check for valid
621      *   postgres users, we might do it here.
622      * ----------------
623      */
624     InitUserid();
625     
626     /* ----------------
627      *  ok, all done, now let's make sure we don't do it again.
628      * ----------------
629      */
630     PostgresIsInitialized = true;
631 /*    on_exitpg(DestroyLocalRelList, (caddr_t) NULL); */
632     
633     /* ----------------
634      *  Done with "InitPostgres", now change to NormalProcessing unless
635      *  we're in BootstrapProcessing mode.
636      * ----------------
637      */
638     if (!bootstrap)
639         SetProcessingMode(NormalProcessing);
640 /*    if (testFlag || lockingOff) */
641     if (lockingOff)
642         LockDisable(true);
643 }
644
645