1 /* 2 * Copyright (c) Facebook, Inc. and its affiliates. 3 * All rights reserved. 4 * 5 * This source code is licensed under the BSD-style license found in the 6 * LICENSE file in the root directory of this source tree. 7 */ 8 9 #include "proxygen/lib/http/connpool/ServerIdleSessionController.h" 10 11 namespace proxygen { 12 getIdleSession()13folly::Future<HTTPSessionBase*> ServerIdleSessionController::getIdleSession() { 14 folly::Promise<HTTPSessionBase*> promise; 15 folly::Future<HTTPSessionBase*> future = promise.getFuture(); 16 SessionPool* maxPool = nullptr; 17 18 { 19 std::lock_guard<std::mutex> lock(lock_); 20 maxPool = popBestIdlePool(); 21 if (markedForDeath_ || !maxPool || !maxPool->getEventBase()) { 22 return folly::makeFuture<HTTPSessionBase*>(nullptr); 23 } 24 } 25 26 if (maxPool->getEventBase()->isInEventBaseThread()) { 27 LOG(ERROR) << "Idle session already belongs to current thread!"; 28 return folly::makeFuture<HTTPSessionBase*>(nullptr); 29 } 30 31 maxPool->getEventBase()->runInEventBaseThread( 32 [this, maxPool, promise = std::move(promise)]() mutable { 33 // Caller (in this case Server::getTransaction()) needs to guarantee 34 // that 'this' still exists. 35 HTTPSessionBase* session = 36 isMarkedForDeath() ? nullptr : maxPool->removeOldestIdleSession(); 37 if (session) { 38 session->detachThreadLocals(true); 39 } 40 promise.setValue(session); 41 }); 42 return future; 43 } 44 addIdleSession(const HTTPSessionBase * session,SessionPool * sessionPool)45void ServerIdleSessionController::addIdleSession(const HTTPSessionBase* session, 46 SessionPool* sessionPool) { 47 std::lock_guard<std::mutex> lock(lock_); 48 if (sessionMap_.find(session) != sessionMap_.end()) { 49 // removeIdleSession should've been called before re-adding 50 LOG(ERROR) << "Session " << session << " already exists!"; 51 return; 52 } 53 if (sessionsByIdleAge_.size() < maxIdleCount_) { 54 auto newIt = sessionsByIdleAge_.insert(sessionsByIdleAge_.end(), 55 {session, sessionPool}); 56 sessionMap_[session] = newIt; 57 } 58 } 59 removeIdleSession(const HTTPSessionBase * session)60void ServerIdleSessionController::removeIdleSession( 61 const HTTPSessionBase* session) { 62 std::lock_guard<std::mutex> lock(lock_); 63 auto it = sessionMap_.find(session); 64 if (it != sessionMap_.end()) { 65 sessionsByIdleAge_.erase(it->second); 66 sessionMap_.erase(it); 67 } 68 } 69 markForDeath()70void ServerIdleSessionController::markForDeath() { 71 std::lock_guard<std::mutex> lock(lock_); 72 markedForDeath_ = true; 73 sessionMap_.clear(); 74 sessionsByIdleAge_.clear(); 75 } 76 77 // must be called under lock_ popBestIdlePool()78SessionPool* FOLLY_NULLABLE ServerIdleSessionController::popBestIdlePool() { 79 if (!sessionsByIdleAge_.empty()) { 80 auto ret = *sessionsByIdleAge_.begin(); 81 sessionsByIdleAge_.erase(sessionsByIdleAge_.begin()); 82 sessionMap_.erase(ret.session); 83 return ret.sessionPool; 84 } 85 return nullptr; 86 } 87 88 } // namespace proxygen 89