SOCI Logo Get SOCI at SourceForge.net. Fast, secure and Free Open Source software downloads

connection-pool.cpp

Go to the documentation of this file.
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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
SourceForge Logo

Generated on Sun Oct 3 2010 17:42:17 for EXTRAS-SOCI by Doxygen 1.7.1