00001 // 00002 // Copyright (C) 2008 Maciej Sobczak 00003 // Distributed under the Boost Software License, Version 1.0. 00004 // (See accompanying file LICENSE_1_0.txt or copy at 00005 // http://www.boost.org/LICENSE_1_0.txt) 00006 // 00007 00008 #define SOCI_SOURCE 00009 #include "connection-pool.h" 00010 #include "error.h" 00011 #include "session.h" 00012 #include <vector> 00013 #include <utility> 00014 00015 #ifndef _WIN32 00016 // POSIX implementation 00017 00018 #include <pthread.h> 00019 #include <sys/time.h> 00020 #include <errno.h> 00021 00022 using namespace soci; 00023 00024 struct connection_pool::connection_pool_impl 00025 { 00026 bool find_free(std::size_t & pos) 00027 { 00028 for (std::size_t i = 0; i != sessions_.size(); ++i) 00029 { 00030 if (sessions_[i].first) 00031 { 00032 pos = i; 00033 return true; 00034 } 00035 } 00036 00037 return false; 00038 } 00039 00040 // by convention, first == true means the entry is free (not used) 00041 std::vector<std::pair<bool, session *> > sessions_; 00042 pthread_mutex_t mtx_; 00043 pthread_cond_t cond_; 00044 }; 00045 00046 connection_pool::connection_pool(std::size_t size) 00047 { 00048 if (size == 0) 00049 { 00050 throw soci_error("Invalid pool size"); 00051 } 00052 00053 pimpl_ = new connection_pool_impl(); 00054 pimpl_->sessions_.resize(size); 00055 for (std::size_t i = 0; i != size; ++i) 00056 { 00057 pimpl_->sessions_[i] = std::make_pair(true, new session()); 00058 } 00059 00060 int cc = pthread_mutex_init(&(pimpl_->mtx_), NULL); 00061 if (cc != 0) 00062 { 00063 throw soci_error("Synchronization error"); 00064 } 00065 00066 cc = pthread_cond_init(&(pimpl_->cond_), NULL); 00067 if (cc != 0) 00068 { 00069 throw soci_error("Synchronization error"); 00070 } 00071 } 00072 00073 connection_pool::~connection_pool() 00074 { 00075 for (std::size_t i = 0; i != pimpl_->sessions_.size(); ++i) 00076 { 00077 delete pimpl_->sessions_[i].second; 00078 } 00079 00080 pthread_mutex_destroy(&(pimpl_->mtx_)); 00081 pthread_cond_destroy(&(pimpl_->cond_)); 00082 00083 delete pimpl_; 00084 } 00085 00086 session & connection_pool::at(std::size_t pos) 00087 { 00088 if (pos >= pimpl_->sessions_.size()) 00089 { 00090 throw soci_error("Invalid pool position"); 00091 } 00092 00093 return *(pimpl_->sessions_[pos].second); 00094 } 00095 00096 std::size_t connection_pool::lease() 00097 { 00098 std::size_t pos; 00099 00100 // no timeout 00101 bool const success = try_lease(pos, -1); 00102 assert(success); 00103 00104 return pos; 00105 } 00106 00107 bool connection_pool::try_lease(std::size_t & pos, int timeout) 00108 { 00109 struct timespec tm; 00110 if (timeout >= 0) 00111 { 00112 // timeout is relative in milliseconds 00113 00114 struct timeval tmv; 00115 gettimeofday(&tmv, NULL); 00116 00117 tm.tv_sec = tmv.tv_sec + timeout / 1000; 00118 tm.tv_nsec = tmv.tv_usec * 1000 + (timeout % 1000) * 1000 * 1000; 00119 } 00120 00121 int cc = pthread_mutex_lock(&(pimpl_->mtx_)); 00122 if (cc != 0) 00123 { 00124 throw soci_error("Synchronization error"); 00125 } 00126 00127 while (pimpl_->find_free(pos) == false) 00128 { 00129 if (timeout < 0) 00130 { 00131 // no timeout, allow unlimited blocking 00132 cc = pthread_cond_wait(&(pimpl_->cond_), &(pimpl_->mtx_)); 00133 } 00134 else 00135 { 00136 // wait with timeout 00137 cc = pthread_cond_timedwait( 00138 &(pimpl_->cond_), &(pimpl_->mtx_), &tm); 00139 } 00140 00141 if (cc == ETIMEDOUT) 00142 { 00143 break; 00144 } 00145 } 00146 00147 if (cc == 0) 00148 { 00149 pimpl_->sessions_[pos].first = false; 00150 } 00151 00152 pthread_mutex_unlock(&(pimpl_->mtx_)); 00153 00154 return cc == 0; 00155 } 00156 00157 void connection_pool::give_back(std::size_t pos) 00158 { 00159 if (pos >= pimpl_->sessions_.size()) 00160 { 00161 throw soci_error("Invalid pool position"); 00162 } 00163 00164 int cc = pthread_mutex_lock(&(pimpl_->mtx_)); 00165 if (cc != 0) 00166 { 00167 throw soci_error("Synchronization error"); 00168 } 00169 00170 if (pimpl_->sessions_[pos].first) 00171 { 00172 pthread_mutex_unlock(&(pimpl_->mtx_)); 00173 throw soci_error("Cannot release pool entry (already free)"); 00174 } 00175 00176 pimpl_->sessions_[pos].first = true; 00177 00178 pthread_mutex_unlock(&(pimpl_->mtx_)); 00179 00180 pthread_cond_signal(&(pimpl_->cond_)); 00181 } 00182 00183 #else 00184 // Windows implementation 00185 00186 #include <Windows.h> 00187 00188 using namespace soci; 00189 00190 struct connection_pool::connection_pool_impl 00191 { 00192 bool find_free(std::size_t & pos) 00193 { 00194 for (std::size_t i = 0; i != sessions_.size(); ++i) 00195 { 00196 if (sessions_[i].first) 00197 { 00198 pos = i; 00199 return true; 00200 } 00201 } 00202 00203 return false; 00204 } 00205 00206 // by convention, first == true means the entry is free (not used) 00207 std::vector<std::pair<bool, session *> > sessions_; 00208 00209 CRITICAL_SECTION mtx_; 00210 HANDLE sem_; 00211 }; 00212 00213 connection_pool::connection_pool(std::size_t size) 00214 { 00215 if (size == 0) 00216 { 00217 throw soci_error("Invalid pool size"); 00218 } 00219 00220 pimpl_ = new connection_pool_impl(); 00221 pimpl_->sessions_.resize(size); 00222 for (std::size_t i = 0; i != size; ++i) 00223 { 00224 pimpl_->sessions_[i] = std::make_pair(true, new session()); 00225 } 00226 00227 InitializeCriticalSection(&(pimpl_->mtx_)); 00228 00229 // initially all entries are available 00230 HANDLE s = CreateSemaphore(NULL, 00231 static_cast<LONG>(size), static_cast<LONG>(size), NULL); 00232 if (s == NULL) 00233 { 00234 throw soci_error("Synchronization error"); 00235 } 00236 00237 pimpl_->sem_ = s; 00238 } 00239 00240 connection_pool::~connection_pool() 00241 { 00242 for (std::size_t i = 0; i != pimpl_->sessions_.size(); ++i) 00243 { 00244 delete pimpl_->sessions_[i].second; 00245 } 00246 00247 DeleteCriticalSection(&(pimpl_->mtx_)); 00248 CloseHandle(pimpl_->sem_); 00249 00250 delete pimpl_; 00251 } 00252 00253 session & connection_pool::at(std::size_t pos) 00254 { 00255 if (pos >= pimpl_->sessions_.size()) 00256 { 00257 throw soci_error("Invalid pool position"); 00258 } 00259 00260 return *(pimpl_->sessions_[pos].second); 00261 } 00262 00263 std::size_t connection_pool::lease() 00264 { 00265 std::size_t pos; 00266 00267 // no timeout 00268 bool const success = try_lease(pos, -1); 00269 assert(success); 00270 00271 return pos; 00272 } 00273 00274 bool connection_pool::try_lease(std::size_t & pos, int timeout) 00275 { 00276 DWORD cc = WaitForSingleObject(pimpl_->sem_, 00277 timeout >= 0 ? static_cast<DWORD>(timeout) : INFINITE); 00278 if (cc == WAIT_OBJECT_0) 00279 { 00280 // semaphore acquired, there is (at least) one free entry 00281 00282 EnterCriticalSection(&(pimpl_->mtx_)); 00283 00284 bool const success = pimpl_->find_free(pos); 00285 assert(success); 00286 00287 pimpl_->sessions_[pos].first = false; 00288 00289 LeaveCriticalSection(&(pimpl_->mtx_)); 00290 00291 return true; 00292 } 00293 else if (cc == WAIT_TIMEOUT) 00294 { 00295 return false; 00296 } 00297 else 00298 { 00299 throw soci_error("Synchronization error"); 00300 } 00301 } 00302 00303 void connection_pool::give_back(std::size_t pos) 00304 { 00305 if (pos >= pimpl_->sessions_.size()) 00306 { 00307 throw soci_error("Invalid pool position"); 00308 } 00309 00310 EnterCriticalSection(&(pimpl_->mtx_)); 00311 00312 if (pimpl_->sessions_[pos].first) 00313 { 00314 LeaveCriticalSection(&(pimpl_->mtx_)); 00315 throw soci_error("Cannot release pool entry (already free)"); 00316 } 00317 00318 pimpl_->sessions_[pos].first = true; 00319 00320 LeaveCriticalSection(&(pimpl_->mtx_)); 00321 00322 ReleaseSemaphore(pimpl_->sem_, 1, NULL); 00323 } 00324 00325 #endif // _WIN32
Generated on Sun Oct 3 2010 17:42:17 for EXTRAS-SOCI by Doxygen 1.7.1