OSDN Git Service

Version number now set in configure, available through Makefile.global
[pg-rex/syncrep.git] / src / backend / utils / init / postinit.c
1 /*-------------------------------------------------------------------------
2  *
3  * postinit.c
4  *        postgres initialization utilities
5  *
6  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.61 2000/07/02 15:20:56 petere Exp $
12  *
13  *
14  *-------------------------------------------------------------------------
15  */
16 #include <fcntl.h>
17 #include <sys/file.h>
18 #include <sys/types.h>
19 #include <math.h>
20 #include <unistd.h>
21
22 #include "postgres.h"
23
24 #include "access/heapam.h"
25 #include "catalog/catname.h"
26 #include "catalog/pg_database.h"
27 #include "libpq/libpq.h"
28 #include "miscadmin.h"
29 #include "storage/backendid.h"
30 #include "storage/proc.h"
31 #include "storage/sinval.h"
32 #include "storage/smgr.h"
33 #include "utils/fmgroids.h"
34 #include "utils/portal.h"
35 #include "utils/relcache.h"
36 #include "utils/syscache.h"
37
38 #ifdef MULTIBYTE
39 #include "mb/pg_wchar.h"
40 #endif
41
42 static void ReverifyMyDatabase(const char *name);
43 static void InitCommunication(void);
44
45 static IPCKey PostgresIpcKey;
46
47 /*** InitPostgres support ***/
48
49
50 /* --------------------------------
51  *              ReverifyMyDatabase
52  *
53  * Since we are forced to fetch the database OID out of pg_database without
54  * benefit of locking or transaction ID checking (see utils/misc/database.c),
55  * we might have gotten a wrong answer.  Or, we might have attached to a
56  * database that's in process of being destroyed by destroydb().  This
57  * routine is called after we have all the locking and other infrastructure
58  * running --- now we can check that we are really attached to a valid
59  * database.
60  *
61  * In reality, if destroydb() is running in parallel with our startup,
62  * it's pretty likely that we will have failed before now, due to being
63  * unable to read some of the system tables within the doomed database.
64  * This routine just exists to make *sure* we have not started up in an
65  * invalid database.  If we quit now, we should have managed to avoid
66  * creating any serious problems.
67  *
68  * This is also a handy place to fetch the database encoding info out
69  * of pg_database, if we are in MULTIBYTE mode.
70  * --------------------------------
71  */
72 static void
73 ReverifyMyDatabase(const char *name)
74 {
75         Relation        pgdbrel;
76         HeapScanDesc pgdbscan;
77         ScanKeyData key;
78         HeapTuple       tup;
79
80         /*
81          * Because we grab AccessShareLock here, we can be sure that destroydb
82          * is not running in parallel with us (any more).
83          */
84         pgdbrel = heap_openr(DatabaseRelationName, AccessShareLock);
85
86         ScanKeyEntryInitialize(&key, 0, Anum_pg_database_datname,
87                                                    F_NAMEEQ, NameGetDatum(name));
88
89         pgdbscan = heap_beginscan(pgdbrel, 0, SnapshotNow, 1, &key);
90
91         tup = heap_getnext(pgdbscan, 0);
92         if (!HeapTupleIsValid(tup) ||
93                 tup->t_data->t_oid != MyDatabaseId)
94         {
95                 /* OOPS */
96                 heap_close(pgdbrel, AccessShareLock);
97
98                 /*
99                  * The only real problem I could have created is to load dirty
100                  * buffers for the dead database into shared buffer cache; if I
101                  * did, some other backend will eventually try to write them and
102                  * die in mdblindwrt.  Flush any such pages to forestall trouble.
103                  */
104                 DropBuffers(MyDatabaseId);
105                 /* Now I can commit hara-kiri with a clear conscience... */
106                 elog(FATAL, "Database '%s', OID %u, has disappeared from pg_database",
107                          name, MyDatabaseId);
108         }
109
110         /*
111          * OK, we're golden.  Only other to-do item is to save the MULTIBYTE
112          * encoding info out of the pg_database tuple.  Note we also set the
113          * "template encoding", which is the default encoding for any CREATE
114          * DATABASE commands executed in this backend; essentially, you get
115          * the same encoding of the database you connected to as the default.
116          * (This replaces code that unreliably grabbed template1's encoding
117          * out of pg_database.  We could do an extra scan to find template1's
118          * tuple, but for 99.99% of all backend startups it'd be wasted cycles
119          * --- and the 'createdb' script connects to template1 anyway, so
120          * there's no difference.)
121          */
122 #ifdef MULTIBYTE
123         SetDatabaseEncoding(((Form_pg_database) GETSTRUCT(tup))->encoding);
124         SetTemplateEncoding(((Form_pg_database) GETSTRUCT(tup))->encoding);
125 #endif
126
127         heap_endscan(pgdbscan);
128         heap_close(pgdbrel, AccessShareLock);
129 }
130
131
132
133 /* --------------------------------
134  *              InitCommunication
135  *
136  *              This routine initializes stuff needed for ipc, locking, etc.
137  *              it should be called something more informative.
138  *
139  * Note:
140  *              This does not set MyBackendId.  MyBackendTag is set, however.
141  * --------------------------------
142  */
143 static void
144 InitCommunication()
145 {
146         char       *postid;                     /* value of environment variable */
147         char       *postport;           /* value of environment variable */
148         char       *ipc_key;            /* value of environemnt variable */
149         IPCKey          key = 0;
150
151         /* ----------------
152          *      try and get the backend tag from POSTID
153          * ----------------
154          */
155         MyBackendId = -1;
156
157         postid = getenv("POSTID");
158         if (!PointerIsValid(postid))
159                 MyBackendTag = -1;
160         else
161         {
162                 MyBackendTag = atoi(postid);
163                 Assert(MyBackendTag >= 0);
164         }
165
166
167         ipc_key = getenv("IPC_KEY");
168         if (!PointerIsValid(ipc_key))
169                 key = -1;
170         else
171         {
172                 key = atoi(ipc_key);
173                 Assert(MyBackendTag >= 0);
174         }
175
176         postport = getenv("POSTPORT");
177
178         if (PointerIsValid(postport))
179         {
180                 if (MyBackendTag == -1)
181                         elog(FATAL, "InitCommunication: missing POSTID");
182         }
183         else if (IsUnderPostmaster)
184         {
185                 elog(FATAL,
186                          "InitCommunication: under postmaster and POSTPORT not set");
187         }
188         else
189         {
190                 /* ----------------
191                  *      assume we're running a postgres backend by itself with
192                  *      no front end or postmaster.
193                  * ----------------
194                  */
195                 if (MyBackendTag == -1)
196                         MyBackendTag = 1;
197
198                 key = PrivateIPCKey;
199         }
200
201         /* ----------------
202          *      initialize shared memory and semaphores appropriately.
203          * ----------------
204          */
205         if (!IsUnderPostmaster)         /* postmaster already did this */
206         {
207                 PostgresIpcKey = key;
208                 AttachSharedMemoryAndSemaphores(key);
209         }
210 }
211
212
213
214 /* --------------------------------
215  * InitPostgres
216  *              Initialize POSTGRES.
217  *
218  * Note:
219  *              Be very careful with the order of calls in the InitPostgres function.
220  * --------------------------------
221  */
222 int                     lockingOff = 0;         /* backend -L switch */
223
224 /*
225  */
226 void
227 InitPostgres(const char *dbname)
228 {
229         bool            bootstrap = IsBootstrapProcessingMode();
230
231         /* ----------------
232          *      initialize the backend local portal stack used by
233          *      internal PQ function calls.  see src/lib/libpq/be-dumpdata.c
234          *      This is different from the "portal manager" so this goes here.
235          *      -cim 2/12/91
236          * ----------------
237          */
238         be_portalinit();
239
240         /* initialize the local buffer manager */
241         InitLocalBuffer();
242
243 #ifndef XLOG
244         if (!TransactionFlushEnabled())
245                 on_shmem_exit(FlushBufferPool, (caddr_t) NULL);
246 #endif
247
248         SetDatabaseName(dbname);
249         /* ----------------
250          *      initialize the database id used for system caches and lock tables
251          * ----------------
252          */
253         if (bootstrap)
254         {
255                 SetDatabasePath(ExpandDatabasePath(dbname));
256                 LockDisable(true);
257         }
258         else
259         {
260                 char       *reason;
261                 char       *fullpath,
262                                         datpath[MAXPGPATH];
263
264                 /* Verify if DataDir is ok */
265                 if (access(DataDir, F_OK) == -1)
266                         elog(FATAL, "Database system not found. Data directory '%s' does not exist.",
267                                  DataDir);
268
269                 ValidatePgVersion(DataDir);
270
271                 /*-----------------
272                  * Find oid and path of the database we're about to open. Since we're
273                  * not yet up and running we have to use the hackish GetRawDatabaseInfo.
274                  *
275                  * OLD COMMENTS:
276                  *              The database's oid forms half of the unique key for the system
277                  *              caches and lock tables.  We therefore want it initialized before
278                  *              we open any relations, since opening relations puts things in the
279                  *              cache.  To get around this problem, this code opens and scans the
280                  *              pg_database relation by hand.
281                  */
282
283                 GetRawDatabaseInfo(dbname, &MyDatabaseId, datpath);
284
285                 if (!OidIsValid(MyDatabaseId))
286                         elog(FATAL,
287                                  "Database \"%s\" does not exist in the system catalog.",
288                                  dbname);
289
290                 fullpath = ExpandDatabasePath(datpath);
291                 if (!fullpath)
292                         elog(FATAL, "Database path could not be resolved.");
293
294                 /* Verify the database path */
295
296                 if (access(fullpath, F_OK) == -1)
297                         elog(FATAL, "Database \"%s\" does not exist. The data directory '%s' is missing.",
298                                  dbname, fullpath);
299
300                 ValidatePgVersion(fullpath);
301
302                 if (chdir(fullpath) == -1)
303                         elog(FATAL, "Unable to change directory to '%s': %s", fullpath, strerror(errno));
304
305                 SetDatabasePath(fullpath);
306         }
307
308         /*
309          * Code after this point assumes we are in the proper directory!
310          */
311
312         /*
313          * Initialize the transaction system and the relation descriptor
314          * cache. Note we have to make certain the lock manager is off while
315          * we do this.
316          */
317         AmiTransactionOverride(IsBootstrapProcessingMode());
318         LockDisable(true);
319
320         /*
321          * Part of the initialization processing done here sets a read lock on
322          * pg_log.      Since locking is disabled the set doesn't have intended
323          * effect of locking out writers, but this is ok, since we only lock
324          * it to examine AMI transaction status, and this is never written
325          * after initdb is done. -mer 15 June 1992
326          */
327         RelationInitialize();           /* pre-allocated reldescs created here */
328         InitializeTransactionSystem();          /* pg_log,etc init/crash recovery
329                                                                                  * here */
330
331         LockDisable(false);
332
333         /*
334          * Set up my per-backend PROC struct in shared memory.
335          */
336         InitProcess(PostgresIpcKey);
337
338         /*
339          * Initialize my entry in the shared-invalidation manager's array of
340          * per-backend data.  (Formerly this came before InitProcess, but now
341          * it must happen after, because it uses MyProc.)  Once I have done
342          * this, I am visible to other backends!
343          *
344          * Sets up MyBackendId, a unique backend identifier.
345          */
346         InitSharedInvalidationState();
347
348         if (MyBackendId > MAXBACKENDS || MyBackendId <= 0)
349         {
350                 elog(FATAL, "cinit2: bad backend id %d (%d)",
351                          MyBackendTag,
352                          MyBackendId);
353         }
354
355         /*
356          * Initialize the access methods. Does not touch files (?) - thomas
357          * 1997-11-01
358          */
359         initam();
360
361         /*
362          * Initialize all the system catalog caches.
363          */
364         zerocaches();
365
366         /*
367          * Does not touch files since all routines are builtins (?) - thomas
368          * 1997-11-01
369          */
370         InitCatalogCache();
371
372         /* start a new transaction here before access to db */
373         if (!bootstrap)
374                 StartTransactionCommand();
375
376         /*
377          * Set ourselves to the proper user id and figure out our postgres
378          * user id.  If we ever add security so that we check for valid
379          * postgres users, we might do it here.
380          */
381         setuid(geteuid());
382         SetUserId();
383
384         if (lockingOff)
385                 LockDisable(true);
386
387         /*
388          * Unless we are bootstrapping, double-check that InitMyDatabaseInfo()
389          * got a correct result.  We can't do this until essentially all the
390          * infrastructure is up, so just do it at the end.
391          */
392         if (!bootstrap)
393                 ReverifyMyDatabase(dbname);
394 }
395
396 void
397 BaseInit(void)
398 {
399         /*
400          * Attach to shared memory and semaphores, and initialize our
401          * input/output/debugging file descriptors.
402          */
403         InitCommunication();
404         DebugFileOpen();
405         smgrinit();
406
407         EnablePortalManager();          /* memory for portal/transaction stuff */
408 }