OSDN Git Service

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