Warning, file /sdk/codevis/thirdparty/soci/src/core/connection-pool.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 // 0002 // Copyright (C) 2008 Maciej Sobczak 0003 // Distributed under the Boost Software License, Version 1.0. 0004 // (See accompanying file LICENSE_1_0.txt or copy at 0005 // http://www.boost.org/LICENSE_1_0.txt) 0006 // 0007 0008 #define SOCI_SOURCE 0009 #include "soci/connection-pool.h" 0010 #include "soci/error.h" 0011 #include "soci/session.h" 0012 #include <vector> 0013 #include <utility> 0014 0015 #ifndef _WIN32 0016 // POSIX implementation 0017 0018 #include <pthread.h> 0019 #include <sys/time.h> 0020 #include <errno.h> 0021 0022 using namespace soci; 0023 0024 struct connection_pool::connection_pool_impl 0025 { 0026 bool find_free(std::size_t & pos) 0027 { 0028 for (std::size_t i = 0; i != sessions_.size(); ++i) 0029 { 0030 if (sessions_[i].first) 0031 { 0032 pos = i; 0033 return true; 0034 } 0035 } 0036 0037 return false; 0038 } 0039 0040 // by convention, first == true means the entry is free (not used) 0041 std::vector<std::pair<bool, session *> > sessions_; 0042 pthread_mutex_t mtx_; 0043 pthread_cond_t cond_; 0044 }; 0045 0046 connection_pool::connection_pool(std::size_t size) 0047 { 0048 if (size == 0) 0049 { 0050 throw soci_error("Invalid pool size"); 0051 } 0052 0053 pimpl_ = new connection_pool_impl(); 0054 pimpl_->sessions_.resize(size); 0055 for (std::size_t i = 0; i != size; ++i) 0056 { 0057 pimpl_->sessions_[i] = std::make_pair(true, new session()); 0058 } 0059 0060 int cc = pthread_mutex_init(&(pimpl_->mtx_), NULL); 0061 if (cc != 0) 0062 { 0063 throw soci_error("Synchronization error"); 0064 } 0065 0066 cc = pthread_cond_init(&(pimpl_->cond_), NULL); 0067 if (cc != 0) 0068 { 0069 throw soci_error("Synchronization error"); 0070 } 0071 } 0072 0073 connection_pool::~connection_pool() 0074 { 0075 for (std::size_t i = 0; i != pimpl_->sessions_.size(); ++i) 0076 { 0077 delete pimpl_->sessions_[i].second; 0078 } 0079 0080 pthread_mutex_destroy(&(pimpl_->mtx_)); 0081 pthread_cond_destroy(&(pimpl_->cond_)); 0082 0083 delete pimpl_; 0084 } 0085 0086 bool connection_pool::try_lease(std::size_t & pos, int timeout) 0087 { 0088 struct timespec tm; 0089 if (timeout >= 0) 0090 { 0091 // timeout is relative in milliseconds 0092 0093 struct timeval tmv; 0094 gettimeofday(&tmv, NULL); 0095 0096 tm.tv_sec = tmv.tv_sec + timeout / 1000; 0097 tm.tv_nsec = tmv.tv_usec * 1000 + (timeout % 1000) * 1000 * 1000; 0098 0099 if (tm.tv_nsec >= 1000 * 1000 * 1000) 0100 { 0101 ++tm.tv_sec; 0102 tm.tv_nsec -= 1000 * 1000 * 1000; 0103 } 0104 } 0105 0106 int cc = pthread_mutex_lock(&(pimpl_->mtx_)); 0107 if (cc != 0) 0108 { 0109 throw soci_error("Synchronization error"); 0110 } 0111 0112 while (pimpl_->find_free(pos) == false) 0113 { 0114 if (timeout < 0) 0115 { 0116 // no timeout, allow unlimited blocking 0117 cc = pthread_cond_wait(&(pimpl_->cond_), &(pimpl_->mtx_)); 0118 } 0119 else 0120 { 0121 // wait with timeout 0122 cc = pthread_cond_timedwait( 0123 &(pimpl_->cond_), &(pimpl_->mtx_), &tm); 0124 } 0125 0126 if (cc == ETIMEDOUT) 0127 { 0128 break; 0129 } 0130 0131 // pthread_cond_timedwait() can apparently return these errors too, 0132 // even if POSIX doesn't document them for the scenario in which we 0133 // call it. 0134 if (cc == EINVAL || cc == EPERM) 0135 { 0136 // We should perhaps throw an exception here, but at the very least 0137 // exit the loop to avoid being stuck in it forever. 0138 break; 0139 } 0140 } 0141 0142 if (cc == 0) 0143 { 0144 pimpl_->sessions_[pos].first = false; 0145 } 0146 0147 pthread_mutex_unlock(&(pimpl_->mtx_)); 0148 0149 if (cc != 0) 0150 { 0151 // we can only fail if timeout expired 0152 if (timeout < 0) 0153 { 0154 throw soci_error("Getting connection from the pool unexpectedly failed"); 0155 } 0156 0157 return false; 0158 } 0159 0160 return true; 0161 } 0162 0163 void connection_pool::give_back(std::size_t pos) 0164 { 0165 if (pos >= pimpl_->sessions_.size()) 0166 { 0167 throw soci_error("Invalid pool position"); 0168 } 0169 0170 int cc = pthread_mutex_lock(&(pimpl_->mtx_)); 0171 if (cc != 0) 0172 { 0173 throw soci_error("Synchronization error"); 0174 } 0175 0176 if (pimpl_->sessions_[pos].first) 0177 { 0178 pthread_mutex_unlock(&(pimpl_->mtx_)); 0179 throw soci_error("Cannot release pool entry (already free)"); 0180 } 0181 0182 pimpl_->sessions_[pos].first = true; 0183 0184 pthread_mutex_unlock(&(pimpl_->mtx_)); 0185 0186 pthread_cond_signal(&(pimpl_->cond_)); 0187 } 0188 0189 #else 0190 // Windows implementation 0191 0192 #include <windows.h> 0193 0194 using namespace soci; 0195 0196 struct connection_pool::connection_pool_impl 0197 { 0198 bool find_free(std::size_t & pos) 0199 { 0200 for (std::size_t i = 0; i != sessions_.size(); ++i) 0201 { 0202 if (sessions_[i].first) 0203 { 0204 pos = i; 0205 return true; 0206 } 0207 } 0208 0209 return false; 0210 } 0211 0212 // by convention, first == true means the entry is free (not used) 0213 std::vector<std::pair<bool, session *> > sessions_; 0214 0215 CRITICAL_SECTION mtx_; 0216 HANDLE sem_; 0217 }; 0218 0219 connection_pool::connection_pool(std::size_t size) 0220 { 0221 if (size == 0) 0222 { 0223 throw soci_error("Invalid pool size"); 0224 } 0225 0226 pimpl_ = new connection_pool_impl(); 0227 pimpl_->sessions_.resize(size); 0228 for (std::size_t i = 0; i != size; ++i) 0229 { 0230 pimpl_->sessions_[i] = std::make_pair(true, new session()); 0231 } 0232 0233 InitializeCriticalSection(&(pimpl_->mtx_)); 0234 0235 // initially all entries are available 0236 HANDLE s = CreateSemaphore(NULL, 0237 static_cast<LONG>(size), static_cast<LONG>(size), NULL); 0238 if (s == NULL) 0239 { 0240 throw soci_error("Synchronization error"); 0241 } 0242 0243 pimpl_->sem_ = s; 0244 } 0245 0246 connection_pool::~connection_pool() 0247 { 0248 for (std::size_t i = 0; i != pimpl_->sessions_.size(); ++i) 0249 { 0250 delete pimpl_->sessions_[i].second; 0251 } 0252 0253 DeleteCriticalSection(&(pimpl_->mtx_)); 0254 CloseHandle(pimpl_->sem_); 0255 0256 delete pimpl_; 0257 } 0258 0259 bool connection_pool::try_lease(std::size_t & pos, int timeout) 0260 { 0261 DWORD cc = WaitForSingleObject(pimpl_->sem_, 0262 timeout >= 0 ? static_cast<DWORD>(timeout) : INFINITE); 0263 if (cc == WAIT_OBJECT_0) 0264 { 0265 // semaphore acquired, there is (at least) one free entry 0266 0267 EnterCriticalSection(&(pimpl_->mtx_)); 0268 0269 if (!pimpl_->find_free(pos)) 0270 { 0271 // this should be impossible 0272 throw soci_error("Getting connection from the pool unexpectedly failed"); 0273 } 0274 0275 pimpl_->sessions_[pos].first = false; 0276 0277 LeaveCriticalSection(&(pimpl_->mtx_)); 0278 0279 return true; 0280 } 0281 else if (cc == WAIT_TIMEOUT) 0282 { 0283 return false; 0284 } 0285 else 0286 { 0287 throw soci_error("Synchronization error"); 0288 } 0289 } 0290 0291 void connection_pool::give_back(std::size_t pos) 0292 { 0293 if (pos >= pimpl_->sessions_.size()) 0294 { 0295 throw soci_error("Invalid pool position"); 0296 } 0297 0298 EnterCriticalSection(&(pimpl_->mtx_)); 0299 0300 if (pimpl_->sessions_[pos].first) 0301 { 0302 LeaveCriticalSection(&(pimpl_->mtx_)); 0303 throw soci_error("Cannot release pool entry (already free)"); 0304 } 0305 0306 pimpl_->sessions_[pos].first = true; 0307 0308 LeaveCriticalSection(&(pimpl_->mtx_)); 0309 0310 ReleaseSemaphore(pimpl_->sem_, 1, NULL); 0311 } 0312 0313 #endif // _WIN32 0314 0315 session & connection_pool::at(std::size_t pos) 0316 { 0317 if (pos >= pimpl_->sessions_.size()) 0318 { 0319 throw soci_error("Invalid pool position"); 0320 } 0321 0322 return *(pimpl_->sessions_[pos].second); 0323 } 0324 0325 std::size_t connection_pool::lease() 0326 { 0327 std::size_t pos SOCI_DUMMY_INIT(0); 0328 0329 // no timeout, so can't fail 0330 try_lease(pos, -1); 0331 0332 return pos; 0333 } 0334 0335