*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.65 2000/11/08 23:24:24 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.66 2000/11/12 20:51:50 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/*
* Check for active backends in the target database.
*/
- if (DatabaseHasActiveBackends(db_id))
+ if (DatabaseHasActiveBackends(db_id, false))
{
heap_close(pgdbrel, AccessExclusiveLock);
elog(ERROR, "DROP DATABASE: database \"%s\" is being accessed by other users", dbname);
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.181 2000/11/09 11:25:59 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.182 2000/11/12 20:51:51 tgl Exp $
*
* NOTES
*
Port *MyBackendPort = NULL;
/* list of active backends. For garbage collection only now. */
-
static Dllist *BackendList;
/* list of ports associated with still open, but incomplete connections */
static Dllist *PortList;
+/* The socket number we are listening for connections on */
int PostPortName;
- /*
- * This is a boolean indicating that there is at least one backend that
- * is accessing the current shared memory and semaphores. Between the
- * time that we start up, or throw away shared memory segments and start
- * over, and the time we generate the next backend (because we received a
- * connection request), it is false. Other times, it is true.
- */
+/*
+ * This is a sequence number that indicates how many times we've had to
+ * throw away the shared memory and start over because we doubted its
+ * integrity. It starts off at zero and is incremented every time we
+ * start over. We use this to ensure that we use a new IPC shared memory
+ * key for the new shared memory segment in case the old segment isn't
+ * entirely gone yet.
+ *
+ * The sequence actually cycles back to 0 after 9, so pathologically there
+ * could be an IPC failure if 10 sets of backends are all stuck and won't
+ * release IPC resources.
+ */
static short shmem_seq = 0;
- /*
- * This is a sequence number that indicates how many times we've had to
- * throw away the shared memory and start over because we doubted its
- * integrity. It starts off at zero and is incremented every time we
- * start over. We use this to ensure that we use a new IPC shared memory
- * key for the new shared memory segment in case the old segment isn't
- * entirely gone yet.
- *
- * The sequence actually cycles back to 0 after 9, so pathologically there
- * could be an IPC failure if 10 sets of backends are all stuck and won't
- * release IPC resources.
- */
-
+/*
+ * This is the base IPC shared memory key. Other keys are generated by
+ * adding to this.
+ */
static IpcMemoryKey ipc_key;
- /*
- * This is the base IPC shared memory key. Other keys are generated by
- * adding to this.
- */
-
+/*
+ * MaxBackends is the actual limit on the number of backends we will
+ * start. The default is established by configure, but it can be
+ * readjusted from 1..MAXBACKENDS with the postmaster -N switch. Note
+ * that a larger MaxBackends value will increase the size of the shared
+ * memory area as well as cause the postmaster to grab more kernel
+ * semaphores, even if you never actually use that many backends.
+ */
int MaxBackends = DEF_MAXBACKENDS;
- /*
- * MaxBackends is the actual limit on the number of backends we will
- * start. The default is established by configure, but it can be
- * readjusted from 1..MAXBACKENDS with the postmaster -N switch. Note
- * that a larger MaxBackends value will increase the size of the shared
- * memory area as well as cause the postmaster to grab more kernel
- * semaphores, even if you never actually use that many backends.
- */
-static int NextBackendTag = INT_MAX; /* XXX why count down not up? */
static char *progname = (char *) NULL;
static char **real_argv;
static int real_argc;
exit(1);
}
+ if (DebugLvl > 2)
+ {
+ extern char **environ;
+ char **p;
+
+ fprintf(stderr, "%s: PostmasterMain: initial environ dump:\n",
+ progname);
+ fprintf(stderr, "-----------------------------------------\n");
+ for (p = environ; *p; ++p)
+ fprintf(stderr, "\t%s\n", *p);
+ fprintf(stderr, "-----------------------------------------\n");
+ }
+
+ /*
+ * Establish input sockets.
+ */
#ifdef USE_SSL
if (EnableSSL && !NetServer)
{
if (NetServer)
{
- status = StreamServerPort(AF_INET, (unsigned short)PostPortName, &ServerSock_INET);
+ status = StreamServerPort(AF_INET, (unsigned short) PostPortName,
+ &ServerSock_INET);
if (status != STATUS_OK)
{
fprintf(stderr, "%s: cannot create INET stream port\n",
}
#ifdef HAVE_UNIX_SOCKETS
- status = StreamServerPort(AF_UNIX, (unsigned short)PostPortName, &ServerSock_UNIX);
+ status = StreamServerPort(AF_UNIX, (unsigned short) PostPortName,
+ &ServerSock_UNIX);
if (status != STATUS_OK)
{
fprintf(stderr, "%s: cannot create UNIX stream port\n",
ExitPostmaster(1);
}
#endif
+
/* set up shared memory and semaphores */
reset_shared(PostPortName);
- /* Init XLOG pathes */
+ /* Init XLOG paths */
snprintf(XLogDir, MAXPGPATH, "%s/pg_xlog", DataDir);
snprintf(ControlFilePath, MAXPGPATH, "%s/global/pg_control", DataDir);
BackendStartup(Port *port)
{
Backend *bn; /* for backend cleanup */
- int pid,
- i;
-
-#ifdef CYR_RECODE
-#define NR_ENVIRONMENT_VBL 5
- char ChTable[80];
-
-#else
-#define NR_ENVIRONMENT_VBL 4
-#endif
-
- static char envEntry[NR_ENVIRONMENT_VBL][2 * ARGV_SIZE];
-
- for (i = 0; i < NR_ENVIRONMENT_VBL; ++i)
- MemSet(envEntry[i], 0, 2 * ARGV_SIZE);
-
- /*
- * Set up the necessary environment variables for the backend This
- * should really be some sort of message....
- */
- sprintf(envEntry[0], "POSTPORT=%d", PostPortName);
- putenv(envEntry[0]);
- sprintf(envEntry[1], "POSTID=%d", NextBackendTag);
- putenv(envEntry[1]);
- sprintf(envEntry[2], "PGDATA=%s", DataDir);
- putenv(envEntry[2]);
- sprintf(envEntry[3], "IPC_KEY=%d", ipc_key);
- putenv(envEntry[3]);
-
-#ifdef CYR_RECODE
- GetCharSetByHost(ChTable, port->raddr.in.sin_addr.s_addr, DataDir);
- if (*ChTable != '\0')
- {
- sprintf(envEntry[4], "PG_RECODETABLE=%s", ChTable);
- putenv(envEntry[4]);
- }
-#endif
+ int pid;
/*
* Compute the cancel key that will be assigned to this backend. The
*/
MyCancelKey = PostmasterRandom();
- if (DebugLvl > 2)
- {
- char **p;
- extern char **environ;
-
- fprintf(stderr, "%s: BackendStartup: environ dump:\n",
- progname);
- fprintf(stderr, "-----------------------------------------\n");
- for (p = environ; *p; ++p)
- fprintf(stderr, "\t%s\n", *p);
- fprintf(stderr, "-----------------------------------------\n");
- }
-
/*
* Flush stdio channels just before fork, to avoid double-output
* problems. Ideally we'd use fflush(NULL) here, but there are still a
/* Specific beos actions before backend startup */
beos_before_backend_startup();
#endif
+
if ((pid = fork()) == 0)
{ /* child */
#ifdef __BEOS__
- /* Specific beos backend stratup actions */
+ /* Specific beos backend startup actions */
beos_backend_startup();
#endif
+
+#ifdef CYR_RECODE
+ {
+ /* Save charset for this host while we still have client addr */
+ char ChTable[80];
+ static char cyrEnvironment[100];
+
+ GetCharSetByHost(ChTable, port->raddr.in.sin_addr.s_addr, DataDir);
+ if (*ChTable != '\0')
+ {
+ snprintf(cyrEnvironment, sizeof(cyrEnvironment),
+ "PG_RECODETABLE=%s", ChTable);
+ putenv(cyrEnvironment);
+ }
+ }
+#endif
+
if (DoBackend(port))
{
fprintf(stderr, "%s child[%d]: BackendStartup: backend startup failed\n",
if (pid < 0)
{
#ifdef __BEOS__
- /* Specific beos backend stratup actions */
+ /* Specific beos backend startup actions */
beos_backend_startup_failed();
#endif
fprintf(stderr, "%s: BackendStartup: fork failed: %s\n",
progname, pid, port->user, port->database,
port->sock);
- /* Generate a new backend tag for every backend we start */
-
- /*
- * XXX theoretically this could wrap around, if you have the patience
- * to start 2^31 backends ...
- */
- NextBackendTag -= 1;
-
/*
* Everything's been successful, it's safe to add this backend to our
* list of backends.
SSDataBase(int xlop)
{
pid_t pid;
- int i;
Backend *bn;
- static char ssEntry[4][2 * ARGV_SIZE];
-
- for (i = 0; i < 4; ++i)
- MemSet(ssEntry[i], 0, 2 * ARGV_SIZE);
-
- sprintf(ssEntry[0], "POSTPORT=%d", PostPortName);
- putenv(ssEntry[0]);
- sprintf(ssEntry[1], "POSTID=%d", NextBackendTag);
- putenv(ssEntry[1]);
- sprintf(ssEntry[2], "PGDATA=%s", DataDir);
- putenv(ssEntry[2]);
- sprintf(ssEntry[3], "IPC_KEY=%d", ipc_key);
- putenv(ssEntry[3]);
fflush(stdout);
fflush(stderr);
ExitPostmaster(1);
}
- NextBackendTag -= 1;
-
if (xlop != BS_XLOG_CHECKPOINT)
return(pid);
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinval.c,v 1.22 2000/11/05 22:50:20 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinval.c,v 1.23 2000/11/12 20:51:51 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/*
* DatabaseHasActiveBackends -- are there any backends running in the given DB
*
+ * If 'ignoreMyself' is TRUE, ignore this particular backend while checking
+ * for backends in the target database.
+ *
* This function is used to interlock DROP DATABASE against there being
* any active backends in the target DB --- dropping the DB while active
* backends remain would be a Bad Thing. Note that we cannot detect here
*/
bool
-DatabaseHasActiveBackends(Oid databaseId)
+DatabaseHasActiveBackends(Oid databaseId, bool ignoreMyself)
{
bool result = false;
SISeg *segP = shmInvalBuffer;
SpinAcquire(SInvalLock);
- for (index = 0; index < segP->maxBackends; index++)
+ for (index = 0; index < segP->lastBackend; index++)
{
SHMEM_OFFSET pOffset = stateP[index].procStruct;
if (proc->databaseId == databaseId)
{
+ if (ignoreMyself && proc == MyProc)
+ continue;
+
result = true;
break;
}
SpinAcquire(SInvalLock);
- for (index = 0; index < segP->maxBackends; index++)
+ for (index = 0; index < segP->lastBackend; index++)
{
SHMEM_OFFSET pOffset = stateP[index].procStruct;
SpinAcquire(SInvalLock);
- for (index = 0; index < segP->maxBackends; index++)
+ for (index = 0; index < segP->lastBackend; index++)
{
SHMEM_OFFSET pOffset = stateP[index].procStruct;
int count = 0;
/*
- * There can be no more than maxBackends active transactions, so this
+ * There can be no more than lastBackend active transactions, so this
* is enough space:
*/
snapshot->xip = (TransactionId *)
- malloc(segP->maxBackends * sizeof(TransactionId));
+ malloc(segP->lastBackend * sizeof(TransactionId));
snapshot->xmin = GetCurrentTransactionId();
SpinAcquire(SInvalLock);
*/
ReadNewTransactionId(&(snapshot->xmax));
- for (index = 0; index < segP->maxBackends; index++)
+ for (index = 0; index < segP->lastBackend; index++)
{
SHMEM_OFFSET pOffset = stateP[index].procStruct;
SpinAcquire(SInvalLock);
- for (index = 0; index < segP->maxBackends; index++)
+ for (index = 0; index < segP->lastBackend; index++)
{
SHMEM_OFFSET pOffset = stateP[index].procStruct;
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinvaladt.c,v 1.34 2000/10/02 21:45:32 petere Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinvaladt.c,v 1.35 2000/11/12 20:51:51 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/* Clear message counters, save size of procState array */
segP->minMsgNum = 0;
segP->maxMsgNum = 0;
+ segP->lastBackend = 0;
segP->maxBackends = maxBackends;
/* The buffer[] array is initially all unused, so we need not fill it */
{
segP->procState[i].nextMsgNum = -1; /* inactive */
segP->procState[i].resetState = false;
- segP->procState[i].tag = InvalidBackendTag;
segP->procState[i].procStruct = INVALID_OFFSET;
}
}
int index;
ProcState *stateP = NULL;
- Assert(MyBackendTag > 0);
-
- /* Check for duplicate backend tags (should never happen) */
- for (index = 0; index < segP->maxBackends; index++)
- {
- if (segP->procState[index].tag == MyBackendTag)
- elog(FATAL, "SIBackendInit: tag %d already in use", MyBackendTag);
- }
-
/* Look for a free entry in the procState array */
- for (index = 0; index < segP->maxBackends; index++)
+ for (index = 0; index < segP->lastBackend; index++)
{
- if (segP->procState[index].tag == InvalidBackendTag)
+ if (segP->procState[index].nextMsgNum < 0) /* inactive slot? */
{
stateP = &segP->procState[index];
break;
}
}
- /*
- * elog() with spinlock held is probably not too cool, but this
- * condition should never happen anyway.
- */
if (stateP == NULL)
{
- elog(NOTICE, "SIBackendInit: no free procState slot available");
- MyBackendId = InvalidBackendTag;
- return 0;
+ if (segP->lastBackend < segP->maxBackends)
+ {
+ stateP = &segP->procState[segP->lastBackend];
+ Assert(stateP->nextMsgNum < 0);
+ segP->lastBackend++;
+ }
+ else
+ {
+ /*
+ * elog() with spinlock held is probably not too cool, but this
+ * condition should never happen anyway.
+ */
+ elog(NOTICE, "SIBackendInit: no free procState slot available");
+ MyBackendId = InvalidBackendId;
+ return 0;
+ }
}
MyBackendId = (stateP - &segP->procState[0]) + 1;
#ifdef INVALIDDEBUG
- elog(DEBUG, "SIBackendInit: backend tag %d; backend id %d.",
- MyBackendTag, MyBackendId);
+ elog(DEBUG, "SIBackendInit: backend id %d", MyBackendId);
#endif /* INVALIDDEBUG */
/* mark myself active, with all extant messages already read */
stateP->nextMsgNum = segP->maxMsgNum;
stateP->resetState = false;
- stateP->tag = MyBackendTag;
stateP->procStruct = MAKE_OFFSET(MyProc);
/* register exit routine to mark my entry inactive at exit */
static void
CleanupInvalidationState(int status, Datum arg)
{
- SISeg *segP = (void*) DatumGetPointer(arg);
+ SISeg *segP = (SISeg *) DatumGetPointer(arg);
+ int i;
Assert(PointerIsValid(segP));
SpinAcquire(SInvalLock);
+ /* Mark myself inactive */
segP->procState[MyBackendId - 1].nextMsgNum = -1;
segP->procState[MyBackendId - 1].resetState = false;
- segP->procState[MyBackendId - 1].tag = InvalidBackendTag;
segP->procState[MyBackendId - 1].procStruct = INVALID_OFFSET;
+ /* Recompute index of last active backend */
+ for (i = segP->lastBackend; i > 0; i--)
+ {
+ if (segP->procState[i - 1].nextMsgNum >= 0)
+ break;
+ }
+ segP->lastBackend = i;
+
SpinRelease(SInvalLock);
}
segP->minMsgNum = 0;
segP->maxMsgNum = 0;
- for (i = 0; i < segP->maxBackends; i++)
+ for (i = 0; i < segP->lastBackend; i++)
{
if (segP->procState[i].nextMsgNum >= 0) /* active backend? */
{
{
ProcState *stateP = &segP->procState[backendId - 1];
- Assert(stateP->tag == MyBackendTag);
-
if (stateP->resetState)
{
/* Recompute minMsgNum = minimum of all backends' nextMsgNum */
- for (i = 0; i < segP->maxBackends; i++)
+ for (i = 0; i < segP->lastBackend; i++)
{
h = segP->procState[i].nextMsgNum;
if (h >= 0)
{
segP->minMsgNum -= MSGNUMWRAPAROUND;
segP->maxMsgNum -= MSGNUMWRAPAROUND;
- for (i = 0; i < segP->maxBackends; i++)
+ for (i = 0; i < segP->lastBackend; i++)
{
if (segP->procState[i].nextMsgNum >= 0)
segP->procState[i].nextMsgNum -= MSGNUMWRAPAROUND;
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/init/globals.c,v 1.46 2000/09/06 14:15:22 petere Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/init/globals.c,v 1.47 2000/11/12 20:51:52 tgl Exp $
*
* NOTES
* Globals used all over the place should be declared here and not
char OutputFileName[MAXPGPATH] = "";
BackendId MyBackendId;
-BackendTag MyBackendTag;
char *DatabaseName = NULL;
char *DatabasePath = NULL;
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.69 2000/10/28 16:20:58 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.70 2000/11/12 20:51:52 tgl Exp $
*
*
*-------------------------------------------------------------------------
*
* This routine initializes stuff needed for ipc, locking, etc.
* it should be called something more informative.
- *
- * Note:
- * This does not set MyBackendId. MyBackendTag is set, however.
* --------------------------------
*/
static void
InitCommunication()
{
- char *postid; /* value of environment variable */
- char *postport; /* value of environment variable */
- char *ipc_key; /* value of environemnt variable */
- IPCKey key = 0;
-
/* ----------------
- * try and get the backend tag from POSTID
+ * initialize shared memory and semaphores appropriately.
* ----------------
*/
- MyBackendId = -1;
-
- postid = getenv("POSTID");
- if (!PointerIsValid(postid))
- MyBackendTag = -1;
- else
- {
- MyBackendTag = atoi(postid);
- Assert(MyBackendTag >= 0);
- }
-
-
- ipc_key = getenv("IPC_KEY");
- if (!PointerIsValid(ipc_key))
- key = -1;
- else
- {
- key = atoi(ipc_key);
- Assert(MyBackendTag >= 0);
- }
-
- postport = getenv("POSTPORT");
-
- if (PointerIsValid(postport))
- {
- if (MyBackendTag == -1)
- elog(FATAL, "InitCommunication: missing POSTID");
- }
- else if (IsUnderPostmaster)
- {
- elog(FATAL,
- "InitCommunication: under postmaster and POSTPORT not set");
- }
- else
+ if (!IsUnderPostmaster) /* postmaster already did this */
{
/* ----------------
- * assume we're running a postgres backend by itself with
+ * we're running a postgres backend by itself with
* no front end or postmaster.
* ----------------
*/
- if (MyBackendTag == -1)
- MyBackendTag = 1;
-
- key = PrivateIPCKey;
- }
-
- /* ----------------
- * initialize shared memory and semaphores appropriately.
- * ----------------
- */
- if (!IsUnderPostmaster) /* postmaster already did this */
- {
+ char *ipc_key; /* value of environment variable */
+ IPCKey key;
+
+ ipc_key = getenv("IPC_KEY");
+
+ if (!PointerIsValid(ipc_key))
+ {
+ /* Normal standalone backend */
+ key = PrivateIPCKey;
+ }
+ else
+ {
+ /* Allow standalone's IPC key to be set */
+ key = atoi(ipc_key);
+ }
PostgresIpcKey = key;
AttachSharedMemoryAndSemaphores(key);
}
*
* Sets up MyBackendId, a unique backend identifier.
*/
+ MyBackendId = InvalidBackendId;
+
InitSharedInvalidationState();
if (MyBackendId > MAXBACKENDS || MyBackendId <= 0)
- {
- elog(FATAL, "cinit2: bad backend id %d (%d)",
- MyBackendTag,
- MyBackendId);
- }
+ elog(FATAL, "cinit2: bad backend id %d", MyBackendId);
/*
* Initialize the access methods. Does not touch files (?) - thomas
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: miscadmin.h,v 1.69 2000/11/04 12:43:24 petere Exp $
+ * $Id: miscadmin.h,v 1.70 2000/11/12 20:51:52 tgl Exp $
*
* NOTES
* some of the information in this file will be moved to
* done in storage/backendid.h for now.
*
* extern BackendId MyBackendId;
- * extern BackendTag MyBackendTag;
*/
extern bool MyDatabaseIdIsInitialized;
extern Oid MyDatabaseId;
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: backendid.h,v 1.7 2000/01/26 05:58:32 momjian Exp $
+ * $Id: backendid.h,v 1.8 2000/11/12 20:51:52 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* -cim 8/17/90
* ----------------
*/
-typedef int16 BackendId; /* unique currently active backend
+typedef int BackendId; /* unique currently active backend
* identifier */
#define InvalidBackendId (-1)
-typedef int32 BackendTag; /* unique backend identifier */
-
-#define InvalidBackendTag (-1)
-
extern BackendId MyBackendId; /* backend id of this backend */
-extern BackendTag MyBackendTag; /* backend tag of this backend */
#endif /* BACKENDID_H */
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: sinval.h,v 1.14 2000/01/26 05:58:33 momjian Exp $
+ * $Id: sinval.h,v 1.15 2000/11/12 20:51:52 tgl Exp $
*
*-------------------------------------------------------------------------
*/
extern void InvalidateSharedInvalid(void (*invalFunction) (),
void (*resetFunction) ());
-extern bool DatabaseHasActiveBackends(Oid databaseId);
+extern bool DatabaseHasActiveBackends(Oid databaseId, bool ignoreMyself);
extern bool TransactionIdIsInProgress(TransactionId xid);
extern void GetXmaxRecent(TransactionId *XmaxRecent);
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: sinvaladt.h,v 1.22 2000/06/15 03:33:00 momjian Exp $
+ * $Id: sinvaladt.h,v 1.23 2000/11/12 20:51:52 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/* nextMsgNum is -1 in an inactive ProcState array entry. */
int nextMsgNum; /* next message number to read, or -1 */
bool resetState; /* true, if backend has to reset its state */
- int tag; /* backend tag received from postmaster */
SHMEM_OFFSET procStruct; /* location of backend's PROC struct */
} ProcState;
*/
int minMsgNum; /* oldest message still needed */
int maxMsgNum; /* next message number to be assigned */
+ int lastBackend; /* index of last active procState entry, +1 */
int maxBackends; /* size of procState array */
/*