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