/* * TransactionLogFetch --- fetch commit status of specified transaction id */ static XidStatus TransactionLogFetch(TransactionId transactionId) { XidStatus xidstatus; /* * Before going to the commit log manager, check our single item cache to * see if we didn't just check the transaction status a moment ago. */ if (TransactionIdEquals(transactionId, cachedFetchXid)) return cachedFetchXidStatus; /* * Also, check to see if the transaction ID is a permanent one. */ if (!TransactionIdIsNormal(transactionId)) { if (TransactionIdEquals(transactionId, BootstrapTransactionId)) return TRANSACTION_STATUS_COMMITTED; if (TransactionIdEquals(transactionId, FrozenTransactionId)) return TRANSACTION_STATUS_COMMITTED; return TRANSACTION_STATUS_ABORTED; } /* * Get the transaction status. */ xidstatus = TransactionIdGetStatus(transactionId); /* * Cache it, but DO NOT cache status for unfinished or sub-committed * transactions! We only cache status that is guaranteed not to change. */ if (xidstatus != TRANSACTION_STATUS_IN_PROGRESS && xidstatus != TRANSACTION_STATUS_SUB_COMMITTED) { TransactionIdStore(transactionId, &cachedFetchXid); cachedFetchXidStatus = xidstatus; } return xidstatus; }
/* * ProcSleep -- put a process to sleep * * P() on the semaphore should put us to sleep. The process * semaphore is cleared by default, so the first time we try * to acquire it, we sleep. * * ASSUME: that no one will fiddle with the queue until after * we release the spin lock. * * NOTES: The process queue is now a priority queue for locking. */ int ProcSleep(PROC_QUEUE *queue, SPINLOCK spinlock, int token, int prio, LOCK *lock) { int i; PROC *proc; #ifndef WIN32 /* figure this out later */ struct itimerval timeval, dummy; #endif /* WIN32 */ proc = (PROC *) MAKE_PTR(queue->links.prev); for (i=0;i<queue->size;i++) { if (proc->prio < prio) proc = (PROC *) MAKE_PTR(proc->links.prev); else break; } MyProc->token = token; MyProc->waitLock = lock; /* ------------------- * currently, we only need this for the ProcWakeup routines * ------------------- */ TransactionIdStore((TransactionId) GetCurrentTransactionId(), &MyProc->xid); /* ------------------- * assume that these two operations are atomic (because * of the spinlock). * ------------------- */ SHMQueueInsertTL(&(proc->links),&(MyProc->links)); queue->size++; SpinRelease(spinlock); /* -------------- * Postgres does not have any deadlock detection code and for this * reason we must set a timer to wake up the process in the event of * a deadlock. For now the timer is set for 1 minute and we assume that * any process which sleeps for this amount of time is deadlocked and will * receive a SIGALRM signal. The handler should release the processes * semaphore and abort the current transaction. * * Need to zero out struct to set the interval and the micro seconds fields * to 0. * -------------- */ #ifndef WIN32 memset(&timeval, 0, sizeof(struct itimerval)); timeval.it_value.tv_sec = DEADLOCK_TIMEOUT; if (setitimer(ITIMER_REAL, &timeval, &dummy)) elog(FATAL, "ProcSleep: Unable to set timer for process wakeup"); #endif /* WIN32 */ /* -------------- * if someone wakes us between SpinRelease and IpcSemaphoreLock, * IpcSemaphoreLock will not block. The wakeup is "saved" by * the semaphore implementation. * -------------- */ IpcSemaphoreLock(MyProc->sem.semId, MyProc->sem.semNum, IpcExclusiveLock); /* --------------- * We were awoken before a timeout - now disable the timer * --------------- */ #ifndef WIN32 timeval.it_value.tv_sec = 0; if (setitimer(ITIMER_REAL, &timeval, &dummy)) elog(FATAL, "ProcSleep: Unable to diable timer for process wakeup"); #endif /* WIN32 */ /* ---------------- * We were assumed to be in a critical section when we went * to sleep. * ---------------- */ SpinAcquire(spinlock); return(MyProc->errType); }