Exemplo n.º 1
0
/*
 * ProcKill() -- Destroy the per-proc data structure for
 *	this process. Release any of its held spin locks.
 */
static void
ProcKill(int exitStatus, int pid)
{
    PROC 		*proc;
    SHMEM_OFFSET	location;
    
    /* -------------------- 
     * If this is a FATAL exit the postmaster will have to kill all the
     * existing backends and reinitialize shared memory.  So all we don't 
     * need to do anything here.
     * --------------------
     */
    if (exitStatus != 0)
	return;
    
    if (! pid)
	{
	    pid = getpid();
	}
    
    ShmemPIDLookup(pid,&location);
    if (location == INVALID_OFFSET)
	return;
    
    proc = (PROC *) MAKE_PTR(location);
    
    if (proc != MyProc) {
	Assert( pid != getpid() );
    } else
	MyProc = NULL;
    
    /* ---------------
     * Assume one lock table.
     * ---------------
     */
    ProcReleaseSpins(proc);
    LockReleaseAll(1,&proc->lockQueue);
    
    /* ----------------
     * get off the wait queue
     * ----------------
     */
    LockLockTable();
    if (proc->links.next != INVALID_OFFSET) {
	Assert(proc->waitLock->waitProcs.size > 0);
	SHMQueueDelete(&(proc->links));
	--proc->waitLock->waitProcs.size;
    }
    SHMQueueElemInit(&(proc->links));
    UnlockLockTable();
    
    return;
}
Exemplo n.º 2
0
/*
 * ProcWakeup -- wake up a process by releasing its private semaphore.
 *
 *   remove the process from the wait queue and set its links invalid.
 *   RETURN: the next process in the wait queue.
 */
PROC *
ProcWakeup(PROC *proc, int errType)
{
    PROC *retProc;
    /* assume that spinlock has been acquired */
    
    if (proc->links.prev == INVALID_OFFSET ||
	proc->links.next == INVALID_OFFSET)
	return((PROC *) NULL);
    
    retProc = (PROC *) MAKE_PTR(proc->links.prev);
    
    /* you have to update waitLock->waitProcs.size yourself */
    SHMQueueDelete(&(proc->links));
    SHMQueueElemInit(&(proc->links));
    
    proc->errType = errType;
    
    IpcSemaphoreUnlock(proc->sem.semId, proc->sem.semNum, IpcExclusiveLock);
    
    return retProc;
}
Exemplo n.º 3
0
/*
 * InitAuxiliaryProcess -- create a per-auxiliary-process data structure
 *
 * This is called by bgwriter and similar processes so that they will have a
 * MyProc value that's real enough to let them wait for LWLocks.  The PGPROC
 * and sema that are assigned are one of the extra ones created during
 * InitProcGlobal.
 *
 * Auxiliary processes are presently not expected to wait for real (lockmgr)
 * locks, so we need not set up the deadlock checker.  They are never added
 * to the ProcArray or the sinval messaging mechanism, either.  They also
 * don't get a VXID assigned, since this is only useful when we actually
 * hold lockmgr locks.
 *
 * Startup process however uses locks but never waits for them in the
 * normal backend sense. Startup process also takes part in sinval messaging
 * as a sendOnly process, so never reads messages from sinval queue. So
 * Startup process does have a VXID and does show up in pg_locks.
 */
void
InitAuxiliaryProcess(void)
{
	PGPROC	   *auxproc;
	int			proctype;

	/*
	 * ProcGlobal should be set up already (if we are a backend, we inherit
	 * this by fork() or EXEC_BACKEND mechanism from the postmaster).
	 */
	if (ProcGlobal == NULL || AuxiliaryProcs == NULL)
		elog(PANIC, "proc header uninitialized");

	if (MyProc != NULL)
		elog(ERROR, "you already exist");

	/*
	 * We use the ProcStructLock to protect assignment and releasing of
	 * AuxiliaryProcs entries.
	 *
	 * While we are holding the ProcStructLock, also copy the current shared
	 * estimate of spins_per_delay to local storage.
	 */
	SpinLockAcquire(ProcStructLock);

	set_spins_per_delay(ProcGlobal->spins_per_delay);

	/*
	 * Find a free auxproc ... *big* trouble if there isn't one ...
	 */
	for (proctype = 0; proctype < NUM_AUXILIARY_PROCS; proctype++)
	{
		auxproc = &AuxiliaryProcs[proctype];
		if (auxproc->pid == 0)
			break;
	}
	if (proctype >= NUM_AUXILIARY_PROCS)
	{
		SpinLockRelease(ProcStructLock);
		elog(FATAL, "all AuxiliaryProcs are in use");
	}

	/* Mark auxiliary proc as in use by me */
	/* use volatile pointer to prevent code rearrangement */
	((volatile PGPROC *) auxproc)->pid = MyProcPid;

	MyProc = auxproc;
	MyPgXact = &ProcGlobal->allPgXact[auxproc->pgprocno];

	SpinLockRelease(ProcStructLock);

	/*
	 * Initialize all fields of MyProc, except for those previously
	 * initialized by InitProcGlobal.
	 */
	SHMQueueElemInit(&(MyProc->links));
	MyProc->waitStatus = STATUS_OK;
	MyProc->lxid = InvalidLocalTransactionId;
	MyProc->fpVXIDLock = false;
	MyProc->fpLocalTransactionId = InvalidLocalTransactionId;
	MyPgXact->xid = InvalidTransactionId;
	MyPgXact->xmin = InvalidTransactionId;
	MyProc->backendId = InvalidBackendId;
	MyProc->databaseId = InvalidOid;
	MyProc->roleId = InvalidOid;
	MyPgXact->delayChkpt = false;
	MyPgXact->vacuumFlags = 0;
	MyProc->lwWaiting = false;
	MyProc->lwWaitMode = 0;
	MyProc->waitLock = NULL;
	MyProc->waitProcLock = NULL;
#ifdef USE_ASSERT_CHECKING
	{
		int			i;

		/* Last process should have released all locks. */
		for (i = 0; i < NUM_LOCK_PARTITIONS; i++)
			Assert(SHMQueueEmpty(&(MyProc->myProcLocks[i])));
	}
#endif

	/*
	 * Acquire ownership of the PGPROC's latch, so that we can use WaitLatch
	 * on it.  That allows us to repoint the process latch, which so far
	 * points to process local one, to the shared one.
	 */
	OwnLatch(&MyProc->procLatch);
	SwitchToSharedLatch();

	/*
	 * We might be reusing a semaphore that belonged to a failed process. So
	 * be careful and reinitialize its value here.  (This is not strictly
	 * necessary anymore, but seems like a good idea for cleanliness.)
	 */
	PGSemaphoreReset(&MyProc->sem);

	/*
	 * Arrange to clean up at process exit.
	 */
	on_shmem_exit(AuxiliaryProcKill, Int32GetDatum(proctype));
}
Exemplo n.º 4
0
/*
 * InitProcess -- initialize a per-process data structure for this backend
 */
void
InitProcess(void)
{
	/* use volatile pointer to prevent code rearrangement */
	volatile PROC_HDR *procglobal = ProcGlobal;

	/*
	 * ProcGlobal should be set up already (if we are a backend, we inherit
	 * this by fork() or EXEC_BACKEND mechanism from the postmaster).
	 */
	if (procglobal == NULL)
		elog(PANIC, "proc header uninitialized");

	if (MyProc != NULL)
		elog(ERROR, "you already exist");

	/*
	 * Try to get a proc struct from the free list.  If this fails, we must be
	 * out of PGPROC structures (not to mention semaphores).
	 *
	 * While we are holding the ProcStructLock, also copy the current shared
	 * estimate of spins_per_delay to local storage.
	 */
	SpinLockAcquire(ProcStructLock);

	set_spins_per_delay(procglobal->spins_per_delay);

	if (IsAnyAutoVacuumProcess())
		MyProc = procglobal->autovacFreeProcs;
	else if (IsBackgroundWorker)
		MyProc = procglobal->bgworkerFreeProcs;
	else
		MyProc = procglobal->freeProcs;

	if (MyProc != NULL)
	{
		if (IsAnyAutoVacuumProcess())
			procglobal->autovacFreeProcs = (PGPROC *) MyProc->links.next;
		else if (IsBackgroundWorker)
			procglobal->bgworkerFreeProcs = (PGPROC *) MyProc->links.next;
		else
			procglobal->freeProcs = (PGPROC *) MyProc->links.next;
		SpinLockRelease(ProcStructLock);
	}
	else
	{
		/*
		 * If we reach here, all the PGPROCs are in use.  This is one of the
		 * possible places to detect "too many backends", so give the standard
		 * error message.  XXX do we need to give a different failure message
		 * in the autovacuum case?
		 */
		SpinLockRelease(ProcStructLock);
		ereport(FATAL,
				(errcode(ERRCODE_TOO_MANY_CONNECTIONS),
				 errmsg("sorry, too many clients already")));
	}
	MyPgXact = &ProcGlobal->allPgXact[MyProc->pgprocno];

	/*
	 * Now that we have a PGPROC, mark ourselves as an active postmaster
	 * child; this is so that the postmaster can detect it if we exit without
	 * cleaning up.  (XXX autovac launcher currently doesn't participate in
	 * this; it probably should.)
	 */
	if (IsUnderPostmaster && !IsAutoVacuumLauncherProcess())
		MarkPostmasterChildActive();

	/*
	 * Initialize all fields of MyProc, except for those previously
	 * initialized by InitProcGlobal.
	 */
	SHMQueueElemInit(&(MyProc->links));
	MyProc->waitStatus = STATUS_OK;
	MyProc->lxid = InvalidLocalTransactionId;
	MyProc->fpVXIDLock = false;
	MyProc->fpLocalTransactionId = InvalidLocalTransactionId;
	MyPgXact->xid = InvalidTransactionId;
	MyPgXact->xmin = InvalidTransactionId;
	MyProc->pid = MyProcPid;
	/* backendId, databaseId and roleId will be filled in later */
	MyProc->backendId = InvalidBackendId;
	MyProc->databaseId = InvalidOid;
	MyProc->roleId = InvalidOid;
	MyPgXact->delayChkpt = false;
	MyPgXact->vacuumFlags = 0;
	/* NB -- autovac launcher intentionally does not set IS_AUTOVACUUM */
	if (IsAutoVacuumWorkerProcess())
		MyPgXact->vacuumFlags |= PROC_IS_AUTOVACUUM;
	MyProc->lwWaiting = false;
	MyProc->lwWaitMode = 0;
	MyProc->waitLock = NULL;
	MyProc->waitProcLock = NULL;
#ifdef USE_ASSERT_CHECKING
	{
		int			i;

		/* Last process should have released all locks. */
		for (i = 0; i < NUM_LOCK_PARTITIONS; i++)
			Assert(SHMQueueEmpty(&(MyProc->myProcLocks[i])));
	}
#endif
	MyProc->recoveryConflictPending = false;

	/* Initialize fields for sync rep */
	MyProc->waitLSN = 0;
	MyProc->syncRepState = SYNC_REP_NOT_WAITING;
	SHMQueueElemInit(&(MyProc->syncRepLinks));

	/*
	 * Acquire ownership of the PGPROC's latch, so that we can use WaitLatch
	 * on it.  That allows us to repoint the process latch, which so far
	 * points to process local one, to the shared one.
	 */
	OwnLatch(&MyProc->procLatch);
	SwitchToSharedLatch();

	/*
	 * We might be reusing a semaphore that belonged to a failed process. So
	 * be careful and reinitialize its value here.  (This is not strictly
	 * necessary anymore, but seems like a good idea for cleanliness.)
	 */
	PGSemaphoreReset(&MyProc->sem);

	/*
	 * Arrange to clean up at backend exit.
	 */
	on_shmem_exit(ProcKill, 0);

	/*
	 * Now that we have a PGPROC, we could try to acquire locks, so initialize
	 * local state needed for LWLocks, and the deadlock checker.
	 */
	InitLWLockAccess();
	InitDeadLockChecking();
}
Exemplo n.º 5
0
/*
 * MarkAsPreparing
 *		Reserve the GID for the given transaction.
 *
 * Internally, this creates a gxact struct and puts it into the active array.
 * NOTE: this is also used when reloading a gxact after a crash; so avoid
 * assuming that we can use very much backend context.
 */
GlobalTransaction
MarkAsPreparing(TransactionId xid, const char *gid,
				TimestampTz prepared_at, Oid owner, Oid databaseid)
{
	GlobalTransaction gxact;
	int			i;

	if (strlen(gid) >= GIDSIZE)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("transaction identifier \"%s\" is too long",
						gid)));

	/* fail immediately if feature is disabled */
	if (max_prepared_xacts == 0)
		ereport(ERROR,
				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
				 errmsg("prepared transactions are disabled"),
			  errhint("Set max_prepared_transactions to a nonzero value.")));

	LWLockAcquire(TwoPhaseStateLock, LW_EXCLUSIVE);

	/*
	 * First, find and recycle any gxacts that failed during prepare. We do
	 * this partly to ensure we don't mistakenly say their GIDs are still
	 * reserved, and partly so we don't fail on out-of-slots unnecessarily.
	 */
	for (i = 0; i < TwoPhaseState->numPrepXacts; i++)
	{
		gxact = TwoPhaseState->prepXacts[i];
		if (!gxact->valid && !TransactionIdIsActive(gxact->locking_xid))
		{
			/* It's dead Jim ... remove from the active array */
			TwoPhaseState->numPrepXacts--;
			TwoPhaseState->prepXacts[i] = TwoPhaseState->prepXacts[TwoPhaseState->numPrepXacts];
			/* and put it back in the freelist */
			gxact->proc.links.next = (SHM_QUEUE *) TwoPhaseState->freeGXacts;
			TwoPhaseState->freeGXacts = gxact;
			/* Back up index count too, so we don't miss scanning one */
			i--;
		}
	}

	/* Check for conflicting GID */
	for (i = 0; i < TwoPhaseState->numPrepXacts; i++)
	{
		gxact = TwoPhaseState->prepXacts[i];
		if (strcmp(gxact->gid, gid) == 0)
		{
			ereport(ERROR,
					(errcode(ERRCODE_DUPLICATE_OBJECT),
					 errmsg("transaction identifier \"%s\" is already in use",
							gid)));
		}
	}

	/* Get a free gxact from the freelist */
	if (TwoPhaseState->freeGXacts == NULL)
		ereport(ERROR,
				(errcode(ERRCODE_OUT_OF_MEMORY),
				 errmsg("maximum number of prepared transactions reached"),
				 errhint("Increase max_prepared_transactions (currently %d).",
						 max_prepared_xacts)));
	gxact = TwoPhaseState->freeGXacts;
	TwoPhaseState->freeGXacts = (GlobalTransaction) gxact->proc.links.next;

	/* Initialize it */
	MemSet(&gxact->proc, 0, sizeof(PGPROC));
	SHMQueueElemInit(&(gxact->proc.links));
	gxact->proc.waitStatus = STATUS_OK;
	/* We set up the gxact's VXID as InvalidBackendId/XID */
	gxact->proc.lxid = (LocalTransactionId) xid;
	gxact->proc.xid = xid;
	gxact->proc.xmin = InvalidTransactionId;
	gxact->proc.pid = 0;
	gxact->proc.backendId = InvalidBackendId;
	gxact->proc.databaseId = databaseid;
	gxact->proc.roleId = owner;
	gxact->proc.inCommit = false;
	gxact->proc.vacuumFlags = 0;
	gxact->proc.lwWaiting = false;
	gxact->proc.lwExclusive = false;
	gxact->proc.lwWaitLink = NULL;
	gxact->proc.waitLock = NULL;
	gxact->proc.waitProcLock = NULL;
	for (i = 0; i < NUM_LOCK_PARTITIONS; i++)
		SHMQueueInit(&(gxact->proc.myProcLocks[i]));
	/* subxid data must be filled later by GXactLoadSubxactData */
	gxact->proc.subxids.overflowed = false;
	gxact->proc.subxids.nxids = 0;

	gxact->prepared_at = prepared_at;
	/* initialize LSN to 0 (start of WAL) */
	gxact->prepare_lsn.xlogid = 0;
	gxact->prepare_lsn.xrecoff = 0;
	gxact->owner = owner;
	gxact->locking_xid = xid;
	gxact->valid = false;
	strcpy(gxact->gid, gid);

	/* And insert it into the active array */
	Assert(TwoPhaseState->numPrepXacts < max_prepared_xacts);
	TwoPhaseState->prepXacts[TwoPhaseState->numPrepXacts++] = gxact;

	LWLockRelease(TwoPhaseStateLock);

	return gxact;
}
Exemplo n.º 6
0
/* --------------------
 * We only get to this routine if we got SIGALRM after DEADLOCK_TIMEOUT
 * while waiting for a lock to be released by some other process.  After
 * the one minute deadline we assume we have a deadlock and must abort
 * this transaction.  We must also indicate that I'm no longer waiting
 * on a lock so that other processes don't try to wake me up and screw 
 * up my semaphore.
 * --------------------
 */
void
HandleDeadLock(int sig)
{
    LOCK *lock;
    int size;
    
    LockLockTable();
    
    /* ---------------------
     * Check to see if we've been awoken by anyone in the interim.
     *
     * If we have we can return and resume our transaction -- happy day.
     * Before we are awoken the process releasing the lock grants it to
     * us so we know that we don't have to wait anymore.
     * 
     * Damn these names are LONG! -mer
     * ---------------------
     */
    if (IpcSemaphoreGetCount(MyProc->sem.semId, MyProc->sem.semNum) == 
	IpcSemaphoreDefaultStartValue) {
	UnlockLockTable();
	return;
    }
    
    /*
     * you would think this would be unnecessary, but...
     *
     * this also means we've been removed already.  in some ports
     * (e.g., sparc and aix) the semop(2) implementation is such that
     * we can actually end up in this handler after someone has removed
     * us from the queue and bopped the semaphore *but the test above
     * fails to detect the semaphore update* (presumably something weird
     * having to do with the order in which the semaphore wakeup signal
     * and SIGALRM get handled).
     */
    if (MyProc->links.prev == INVALID_OFFSET ||
	MyProc->links.next == INVALID_OFFSET) {
	UnlockLockTable();
	return;
    }
    
    lock = MyProc->waitLock;
    size = lock->waitProcs.size; /* so we can look at this in the core */
    
    /* ------------------------
     * Get this process off the lock's wait queue
     * ------------------------
     */
    Assert(lock->waitProcs.size > 0);
    --lock->waitProcs.size;
    SHMQueueDelete(&(MyProc->links));
    SHMQueueElemInit(&(MyProc->links));
    
    /* ------------------
     * Unlock my semaphore so that the count is right for next time.
     * I was awoken by a signal, not by someone unlocking my semaphore.
     * ------------------
     */
    IpcSemaphoreUnlock(MyProc->sem.semId, MyProc->sem.semNum, IpcExclusiveLock);
    
    /* -------------
     * Set MyProc->errType to STATUS_ERROR so that we abort after
     * returning from this handler.
     * -------------
     */
    MyProc->errType = STATUS_ERROR;
    
    /*
     * if this doesn't follow the IpcSemaphoreUnlock then we get lock
     * table corruption ("LockReplace: xid table corrupted") due to
     * race conditions.  i don't claim to understand this...
     */
    UnlockLockTable();
    
    elog(NOTICE, "Timeout -- possible deadlock");
    return;
}
Exemplo n.º 7
0
/* ------------------------
 * InitProc -- create a per-process data structure for this process
 * used by the lock manager on semaphore queues.
 * ------------------------
 */
void
InitProcess(IPCKey key)
{
    bool found = false;
    int pid;
    int semstat;
    unsigned long location, myOffset;
    
    /* ------------------
     * Routine called if deadlock timer goes off. See ProcSleep()
     * ------------------
     */
#ifndef WIN32
    signal(SIGALRM, HandleDeadLock);
#endif /* WIN32 we'll have to figure out how to handle this later */

    SpinAcquire(ProcStructLock);
    
    /* attach to the free list */
    ProcGlobal = (PROC_HDR *)
	ShmemInitStruct("Proc Header",(unsigned)sizeof(PROC_HDR),&found);
    if (!found) {
	/* this should not happen. InitProcGlobal() is called before this. */
	elog(WARN, "InitProcess: Proc Header uninitialized");
    }
    
    if (MyProc != NULL)
	{
	    SpinRelease(ProcStructLock);
	    elog(WARN,"ProcInit: you already exist");
	    return;
	}
    
    /* try to get a proc from the free list first */
    
    myOffset = ProcGlobal->freeProcs;
    
    if (myOffset != INVALID_OFFSET)
	{
	    MyProc = (PROC *) MAKE_PTR(myOffset);
	    ProcGlobal->freeProcs = MyProc->links.next;
	}
    else
	{
	    /* have to allocate one.  We can't use the normal binding
	     * table mechanism because the proc structure is stored
	     * by PID instead of by a global name (need to look it
	     * up by PID when we cleanup dead processes).
	     */
	    
	    MyProc = (PROC *) ShmemAlloc((unsigned)sizeof(PROC));
	    if (! MyProc)
		{
		    SpinRelease(ProcStructLock);
		    elog (FATAL,"cannot create new proc: out of memory");
		}
	    
	    /* this cannot be initialized until after the buffer pool */
	    SHMQueueInit(&(MyProc->lockQueue));
	    MyProc->procId = ProcGlobal->numProcs;
	    ProcGlobal->numProcs++;
	}
    
    /*
     * zero out the spin lock counts and set the sLocks field for
     * ProcStructLock to 1 as we have acquired this spinlock above but 
     * didn't record it since we didn't have MyProc until now.
     */
    memset(MyProc->sLocks, 0, sizeof(MyProc->sLocks));
    MyProc->sLocks[ProcStructLock] = 1;


    if (IsUnderPostmaster) {
	IPCKey semKey;
	int semNum;
	int semId;
	union semun semun;

	ProcGetNewSemKeyAndNum(&semKey, &semNum);
	
	semId = IpcSemaphoreCreate(semKey,
				   PROC_NSEMS_PER_SET,
				   IPCProtection,
				   IpcSemaphoreDefaultStartValue,
				   0,
				   &semstat);
	/*
	 * we might be reusing a semaphore that belongs to a dead
	 * backend. So be careful and reinitialize its value here.
	 */
	semun.val = IpcSemaphoreDefaultStartValue;
	semctl(semId, semNum, SETVAL, semun);

	IpcSemaphoreLock(semId, semNum, IpcExclusiveLock);
	MyProc->sem.semId = semId;
	MyProc->sem.semNum = semNum;
	MyProc->sem.semKey = semKey;
    } else {
	MyProc->sem.semId = -1;
    }
    
    /* ----------------------
     * Release the lock.
     * ----------------------
     */
    SpinRelease(ProcStructLock);
    
    MyProc->pid = 0;
#if 0
    MyProc->pid = MyPid;
#endif
    
    /* ----------------
     * Start keeping spin lock stats from here on.  Any botch before
     * this initialization is forever botched
     * ----------------
     */
    memset(MyProc->sLocks, 0, MAX_SPINS*sizeof(*MyProc->sLocks));
    
    /* -------------------------
     * Install ourselves in the binding table.  The name to
     * use is determined by the OS-assigned process id.  That
     * allows the cleanup process to find us after any untimely
     * exit.
     * -------------------------
     */
    pid = getpid();
    location = MAKE_OFFSET(MyProc);
    if ((! ShmemPIDLookup(pid,&location)) || (location != MAKE_OFFSET(MyProc)))
	{
	    elog(FATAL,"InitProc: ShmemPID table broken");
	}
    
    MyProc->errType = NO_ERROR;
    SHMQueueElemInit(&(MyProc->links));
    
    on_exitpg(ProcKill, (caddr_t)pid);
    
    ProcInitialized = TRUE;
}
Exemplo n.º 8
0
/*
 * InitAuxiliaryProcess -- create a per-auxiliary-process data structure
 *
 * This is called by bgwriter and similar processes so that they will have a
 * MyProc value that's real enough to let them wait for LWLocks.  The PGPROC
 * and sema that are assigned are one of the extra ones created during
 * InitProcGlobal.
 *
 * Auxiliary processes are presently not expected to wait for real (lockmgr)
 * locks, so we need not set up the deadlock checker.  They are never added
 * to the ProcArray or the sinval messaging mechanism, either.	They also
 * don't get a VXID assigned, since this is only useful when we actually
 * hold lockmgr locks.
 */
void
InitAuxiliaryProcess(void)
{
	PGPROC	   *auxproc;
	int			proctype;
	int			i;

	/*
	 * ProcGlobal should be set up already (if we are a backend, we inherit
	 * this by fork() or EXEC_BACKEND mechanism from the postmaster).
	 */
	if (ProcGlobal == NULL || AuxiliaryProcs == NULL)
		elog(PANIC, "proc header uninitialized");

	if (MyProc != NULL)
		elog(ERROR, "you already exist");

	/*
	 * Find a free auxproc entry. Use compare_and_swap to avoid locking.
	 */
	for (proctype = 0; proctype < NUM_AUXILIARY_PROCS; proctype++)
	{
		auxproc = &AuxiliaryProcs[proctype];
		if (compare_and_swap_32((uint32*)(&(auxproc->pid)),
								0,
								MyProcPid))
		{
			/* Find a free entry, break here. */
			break;
		}
	}
	
	if (proctype >= NUM_AUXILIARY_PROCS)
	{
		elog(FATAL, "all AuxiliaryProcs are in use");
	}

	set_spins_per_delay(ProcGlobal->spins_per_delay);

	MyProc = auxproc;
	lockHolderProcPtr = auxproc;

	/*
	 * Initialize all fields of MyProc, except for the semaphore which was
	 * prepared for us by InitProcGlobal.
	 */
	SHMQueueElemInit(&(MyProc->links));
	MyProc->waitStatus = STATUS_OK;
	MyProc->xid = InvalidTransactionId;
	MyProc->xmin = InvalidTransactionId;
	MyProc->databaseId = InvalidOid;
	MyProc->roleId = InvalidOid;
    MyProc->mppLocalProcessSerial = 0;
    MyProc->mppSessionId = 0;
    MyProc->mppIsWriter = false;
	MyProc->inVacuum = false;
	MyProc->postmasterResetRequired = true;
	MyProc->lwWaiting = false;
	MyProc->lwExclusive = false;
	MyProc->lwWaitLink = NULL;
	MyProc->waitLock = NULL;
	MyProc->waitProcLock = NULL;
	for (i = 0; i < NUM_LOCK_PARTITIONS; i++)
		SHMQueueInit(&(MyProc->myProcLocks[i]));

	/*
	 * We might be reusing a semaphore that belonged to a failed process. So
	 * be careful and reinitialize its value here.	(This is not strictly
	 * necessary anymore, but seems like a good idea for cleanliness.)
	 */
	PGSemaphoreReset(&MyProc->sem);

	MyProc->queryCommandId = -1;

	/*
	 * Arrange to clean up at process exit.
	 */
	on_shmem_exit(AuxiliaryProcKill, Int32GetDatum(proctype));
}
Exemplo n.º 9
0
/*
 * InitProcess -- initialize a per-process data structure for this backend
 */
void
InitProcess(void)
{
	/* use volatile pointer to prevent code rearrangement */
	volatile PROC_HDR *procglobal = ProcGlobal;
	int			i;

	/*
	 * ProcGlobal should be set up already (if we are a backend, we inherit
	 * this by fork() or EXEC_BACKEND mechanism from the postmaster).
	 */
	if (procglobal == NULL)
		elog(PANIC, "proc header uninitialized");

	if (MyProc != NULL)
		elog(ERROR, "you already exist");

	MyProc = RemoveFirst();
	
	if (MyProc == NULL)
	{
		ereport(FATAL,
				(errcode(ERRCODE_TOO_MANY_CONNECTIONS),
				 errmsg("sorry, too many clients already")));
	}
	
	if (gp_debug_pgproc)
	{
		elog(LOG, "allocating PGPROC entry for pid %d, freeProcs (prev offset, new offset): (%ld, %ld)",
			 MyProcPid, MAKE_OFFSET(MyProc), MyProc->links.next);
	}

	set_spins_per_delay(procglobal->spins_per_delay);

	int mppLocalProcessSerial = gp_atomic_add_32(&procglobal->mppLocalProcessCounter, 1);

	lockHolderProcPtr = MyProc;

	/* Set the next pointer to INVALID_OFFSET */
	MyProc->links.next = INVALID_OFFSET;

	/*
	 * Initialize all fields of MyProc, except for the semaphore which was
	 * prepared for us by InitProcGlobal.
	 */
	SHMQueueElemInit(&(MyProc->links));
	MyProc->waitStatus = STATUS_OK;
	MyProc->xid = InvalidTransactionId;
	MyProc->xmin = InvalidTransactionId;
	MyProc->pid = MyProcPid;
	/* databaseId and roleId will be filled in later */
	MyProc->databaseId = InvalidOid;
	MyProc->roleId = InvalidOid;
	MyProc->inVacuum = false;
	MyProc->postmasterResetRequired = true;
	MyProc->lwWaiting = false;
	MyProc->lwExclusive = false;
	MyProc->lwWaitLink = NULL;
	MyProc->waitLock = NULL;
	MyProc->waitProcLock = NULL;
	for (i = 0; i < NUM_LOCK_PARTITIONS; i++)
		SHMQueueInit(&(MyProc->myProcLocks[i]));

    /* 
     * mppLocalProcessSerial uniquely identifies this backend process among
     * all those that our parent postmaster process creates over its lifetime. 
     *
  	 * Since we use the process serial number to decide if we should
	 * deliver a response from a server under this spin, we need to 
	 * assign it under the spin lock.
	 */
    MyProc->mppLocalProcessSerial = mppLocalProcessSerial;

    /* 
     * A nonzero gp_session_id uniquely identifies an MPP client session 
     * over the lifetime of the entry postmaster process.  A qDisp passes
     * its gp_session_id down to all of its qExecs.  If this is a qExec,
     * we have already received the gp_session_id from the qDisp.
     */
    elog(DEBUG1,"InitProcess(): gp_session_id %d", gp_session_id);
    if (Gp_role == GP_ROLE_DISPATCH && gp_session_id == -1)
        gp_session_id = mppLocalProcessSerial;
    MyProc->mppSessionId = gp_session_id;
    
    MyProc->mppIsWriter = Gp_is_writer;

	/*
	 * We might be reusing a semaphore that belonged to a failed process. So
	 * be careful and reinitialize its value here.	(This is not strictly
	 * necessary anymore, but seems like a good idea for cleanliness.)
	 */
	PGSemaphoreReset(&MyProc->sem);

	/* Set wait portal (do not check if resource scheduling is enabled) */
	MyProc->waitPortalId = INVALID_PORTALID;

	MyProc->queryCommandId = -1;

	/*
	 * Arrange to clean up at backend exit.
	 */
	on_shmem_exit(ProcKill, 0);

	/*
	 * Now that we have a PGPROC, we could try to acquire locks, so initialize
	 * the deadlock checker.
	 */
	InitDeadLockChecking();
}