OSDN Git Service

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