void signalHandler(int signalId) { switch(signalId) { case SIGHUP: /* Restart server: */ { Threads::MutexCond::Lock shutdownLock(shutdownCond); shutdown=false; shutdownCond.broadcast(); } break; case SIGINT: case SIGTERM: /* Shut down server: */ { Threads::MutexCond::Lock shutdownLock(shutdownCond); shutdown=true; shutdownCond.broadcast(); } break; } return; }
WiredTigerSession* WiredTigerSessionCache::getSession() { boost::shared_lock<boost::shared_mutex> shutdownLock(_shutdownLock); // We should never be able to get here after _shuttingDown is set, because no new // operations should be allowed to start. invariant(!_shuttingDown.loadRelaxed()); // Set the high water mark if we need to if (_sessionsOut.fetchAndAdd(1) > _highWaterMark.load()) { _highWaterMark.store(_sessionsOut.load()); } if (!_sessions.empty()) { stdx::lock_guard<SpinLock> lock(_cacheLock); if (!_sessions.empty()) { // Get the most recently used session so that if we discard sessions, we're // discarding older ones WiredTigerSession* cachedSession = _sessions.back(); _sessions.pop_back(); sessionsInCache.fetchAndSubtract(1); return cachedSession; } } // Outside of the cache partition lock, but on release will be put back on the cache return new WiredTigerSession(_conn, _epoch); }
void WiredTigerSessionCache::releaseSession(WiredTigerSession* session) { invariant(session); invariant(session->cursorsOut() == 0); boost::shared_lock<boost::shared_mutex> shutdownLock(_shutdownLock); if (_shuttingDown.loadRelaxed()) { // Leak the session in order to avoid race condition with clean shutdown, where the // storage engine is ripped from underneath transactions, which are not "active" // (i.e., do not have any locks), but are just about to delete the recovery unit. // See SERVER-16031 for more information. return; } // This checks that we are only caching idle sessions and not something which might hold // locks or otherwise prevent truncation. { WT_SESSION* ss = session->getSession(); uint64_t range; invariantWTOK(ss->transaction_pinned_range(ss, &range)); invariant(range == 0); } _sessionsOut.fetchAndSubtract(1); bool returnedToCache = false; invariant(session->_getEpoch() <= _epoch); // Only return sessions until we hit the maximum number of sessions we have ever seen demand // for concurrently. We also want to immediately delete any session that is from a // non-current epoch. if (session->_getEpoch() == _epoch && sessionsInCache.load() < _highWaterMark.load()) { returnedToCache = true; stdx::lock_guard<SpinLock> lock(_cacheLock); _sessions.push_back(session); } if (returnedToCache) { sessionsInCache.fetchAndAdd(1); } else { delete session; } if (_engine && _engine->haveDropsQueued()) { _engine->dropAllQueued(); } if (_engine && _engine->haveDropsQueued()) { _engine->dropAllQueued(); } }
void MessageEndpoint::Shutdown() { { Lock shutdownLock(&m_isShutdownMutex); m_isShutDown = true; } //Shut down each MessageQueue std::vector<uint32_t> serials = m_queues.GetUsedSerials(); for(uint i = 0; i < serials.size(); i++) { MessageQueue *queue = m_queues.GetByOurSerial(serials[i]); if(queue != NULL) { queue->Shutdown(); } } pthread_cond_signal(&m_callbackWakeupCondition); }
//blocking call Message *MessageEndpoint::PopMessage(Ticket &ticket, int timeout) { Message *ret; MessageQueue *queue = m_queues.GetByOurSerial(ticket.m_ourSerialNum); if(queue == NULL) { //Tried to read from a queue, but it didn't exist. We must have closed it, and then tried reading. // This is a protocol error return new ErrorMessage(ERROR_PROTOCOL_MISTAKE); } //TODO: This is not quite right. We should keep returning valid messages as long as // we have them. We should ask the MessageQueue for a new message (maybe peek?) // and only return a shutdown message if one doesn't exist there. //If we're shut down, then return a shutdown message { Lock shutdownLock(&m_isShutdownMutex); if(m_isShutDown) { return new ErrorMessage(ERROR_SOCKET_CLOSED); } } ret = queue->PopMessage(timeout); if(ret->m_messageType == ERROR_MESSAGE) { ErrorMessage *error = (ErrorMessage*)ret; if(error->m_errorType == ERROR_TIMEOUT) { m_consecutiveTimeouts++; //TODO: deal with timeouts } } return ret; }
GlobalRWLock::~GlobalRWLock() { if (cachedLock) shutdownLock(); }
bool MessageEndpoint::PushMessage(Message *message) { uint32_t ourSerial; bool isNewCallback = false; if(message == NULL) { return false; } { Lock shutdownLock(&m_isShutdownMutex); if(m_isShutDown) { message->DeleteContents(); delete message; return false; } } //The other endpoint must always provide a valid "our" serial number, ignore if they don't if(message->m_ourSerialNumber == 0) { message->DeleteContents(); delete message; return false; } //If this is a new conversation from the endpoint (new callback conversation) if(message->m_theirSerialNumber == 0) { isNewCallback = true; //Look up to see if there's a MessageQueue for this serial MessageQueue *queue = m_queues.GetByTheirSerial(message->m_ourSerialNumber); //If this is a brand new callback message if(queue == NULL) { ourSerial = GetNextOurSerialNum(); m_queues.AddQueue(ourSerial, message->m_ourSerialNumber); queue = m_queues.GetByOurSerial(ourSerial); //It's possible to have a race condition that would delete this MessageQueue before we could access it if(queue == NULL) { message->DeleteContents(); delete message; return false; } } if(queue->PushMessage(message)) { if(isNewCallback) { { Lock lock(&m_availableCBsMutex); m_availableCBs.push(ourSerial); } pthread_cond_signal(&m_callbackWakeupCondition); } return true; } else { return false; } } //If we got here, the message should be for an existing conversation // (IE: Both serials should be valid) MessageQueue *queue = m_queues.GetByOurSerial(message->m_theirSerialNumber); if(queue == NULL) { //If there wasn't a MessageQueue for this serial number, then this message must be late or in error message->DeleteContents(); delete message; return false; } //Update the MessageQueue to have the received "their" serial. It might not have it yet. m_queues.AddQueue(message->m_theirSerialNumber, message->m_ourSerialNumber); return queue->PushMessage(message); }