connection-pool.cpp
Go to the documentation of this file.
1 //
2 // Copyright (C) 2008 Maciej Sobczak
3 // Distributed under the Boost Software License, Version 1.0.
4 // (See accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
6 //
7 
8 #define SOCI_SOURCE
9 #include "connection-pool.h"
10 #include "error.h"
11 #include "session.h"
12 #include <vector>
13 #include <utility>
14 
15 #ifndef _WIN32
16 // POSIX implementation
17 
18 #include <pthread.h>
19 #include <sys/time.h>
20 #include <errno.h>
21 
22 using namespace soci;
23 
25 {
26  bool find_free(std::size_t & pos)
27  {
28  for (std::size_t i = 0; i != sessions_.size(); ++i)
29  {
30  if (sessions_[i].first)
31  {
32  pos = i;
33  return true;
34  }
35  }
36 
37  return false;
38  }
39 
40  // by convention, first == true means the entry is free (not used)
41  std::vector<std::pair<bool, session *> > sessions_;
42  pthread_mutex_t mtx_;
43  pthread_cond_t cond_;
44 };
45 
47 {
48  if (size == 0)
49  {
50  throw soci_error("Invalid pool size");
51  }
52 
54  pimpl_->sessions_.resize(size);
55  for (std::size_t i = 0; i != size; ++i)
56  {
57  pimpl_->sessions_[i] = std::make_pair(true, new session());
58  }
59 
60  int cc = pthread_mutex_init(&(pimpl_->mtx_), NULL);
61  if (cc != 0)
62  {
63  throw soci_error("Synchronization error");
64  }
65 
66  cc = pthread_cond_init(&(pimpl_->cond_), NULL);
67  if (cc != 0)
68  {
69  throw soci_error("Synchronization error");
70  }
71 }
72 
74 {
75  for (std::size_t i = 0; i != pimpl_->sessions_.size(); ++i)
76  {
77  delete pimpl_->sessions_[i].second;
78  }
79 
80  pthread_mutex_destroy(&(pimpl_->mtx_));
81  pthread_cond_destroy(&(pimpl_->cond_));
82 
83  delete pimpl_;
84 }
85 
86 session & connection_pool::at(std::size_t pos)
87 {
88  if (pos >= pimpl_->sessions_.size())
89  {
90  throw soci_error("Invalid pool position");
91  }
92 
93  return *(pimpl_->sessions_[pos].second);
94 }
95 
97 {
98  std::size_t pos;
99 
100  // no timeout
101 #ifdef NDEBUG
102  try_lease(pos, -1);
103 #else
104  bool const success = try_lease(pos, -1);
105 #endif
106  assert(success);
107 
108  return pos;
109 }
110 
111 bool connection_pool::try_lease(std::size_t & pos, int timeout)
112 {
113  struct timespec tm;
114  if (timeout >= 0)
115  {
116  // timeout is relative in milliseconds
117 
118  struct timeval tmv;
119  gettimeofday(&tmv, NULL);
120 
121  tm.tv_sec = tmv.tv_sec + timeout / 1000;
122  tm.tv_nsec = tmv.tv_usec * 1000 + (timeout % 1000) * 1000 * 1000;
123 
124  if (tm.tv_nsec >= 1000 * 1000 * 1000)
125  {
126  ++tm.tv_sec;
127  tm.tv_nsec -= 1000 * 1000 * 1000;
128  }
129  }
130 
131  int cc = pthread_mutex_lock(&(pimpl_->mtx_));
132  if (cc != 0)
133  {
134  throw soci_error("Synchronization error");
135  }
136 
137  while (pimpl_->find_free(pos) == false)
138  {
139  if (timeout < 0)
140  {
141  // no timeout, allow unlimited blocking
142  cc = pthread_cond_wait(&(pimpl_->cond_), &(pimpl_->mtx_));
143  }
144  else
145  {
146  // wait with timeout
147  cc = pthread_cond_timedwait(
148  &(pimpl_->cond_), &(pimpl_->mtx_), &tm);
149  }
150 
151  if (cc == ETIMEDOUT)
152  {
153  break;
154  }
155  }
156 
157  if (cc == 0)
158  {
159  pimpl_->sessions_[pos].first = false;
160  }
161 
162  pthread_mutex_unlock(&(pimpl_->mtx_));
163 
164  return cc == 0;
165 }
166 
167 void connection_pool::give_back(std::size_t pos)
168 {
169  if (pos >= pimpl_->sessions_.size())
170  {
171  throw soci_error("Invalid pool position");
172  }
173 
174  int cc = pthread_mutex_lock(&(pimpl_->mtx_));
175  if (cc != 0)
176  {
177  throw soci_error("Synchronization error");
178  }
179 
180  if (pimpl_->sessions_[pos].first)
181  {
182  pthread_mutex_unlock(&(pimpl_->mtx_));
183  throw soci_error("Cannot release pool entry (already free)");
184  }
185 
186  pimpl_->sessions_[pos].first = true;
187 
188  pthread_mutex_unlock(&(pimpl_->mtx_));
189 
190  pthread_cond_signal(&(pimpl_->cond_));
191 }
192 
193 #else
194 // Windows implementation
195 
196 #include <windows.h>
197 
198 using namespace soci;
199 
201 {
202  bool find_free(std::size_t & pos)
203  {
204  for (std::size_t i = 0; i != sessions_.size(); ++i)
205  {
206  if (sessions_[i].first)
207  {
208  pos = i;
209  return true;
210  }
211  }
212 
213  return false;
214  }
215 
216  // by convention, first == true means the entry is free (not used)
217  std::vector<std::pair<bool, session *> > sessions_;
218 
219  CRITICAL_SECTION mtx_;
220  HANDLE sem_;
221 };
222 
223 connection_pool::connection_pool(std::size_t size)
224 {
225  if (size == 0)
226  {
227  throw soci_error("Invalid pool size");
228  }
229 
231  pimpl_->sessions_.resize(size);
232  for (std::size_t i = 0; i != size; ++i)
233  {
234  pimpl_->sessions_[i] = std::make_pair(true, new session());
235  }
236 
237  InitializeCriticalSection(&(pimpl_->mtx_));
238 
239  // initially all entries are available
240  HANDLE s = CreateSemaphore(NULL,
241  static_cast<LONG>(size), static_cast<LONG>(size), NULL);
242  if (s == NULL)
243  {
244  throw soci_error("Synchronization error");
245  }
246 
247  pimpl_->sem_ = s;
248 }
249 
251 {
252  for (std::size_t i = 0; i != pimpl_->sessions_.size(); ++i)
253  {
254  delete pimpl_->sessions_[i].second;
255  }
256 
257  DeleteCriticalSection(&(pimpl_->mtx_));
258  CloseHandle(pimpl_->sem_);
259 
260  delete pimpl_;
261 }
262 
263 session & connection_pool::at(std::size_t pos)
264 {
265  if (pos >= pimpl_->sessions_.size())
266  {
267  throw soci_error("Invalid pool position");
268  }
269 
270  return *(pimpl_->sessions_[pos].second);
271 }
272 
273 std::size_t connection_pool::lease()
274 {
275  std::size_t pos;
276 
277  // no timeout
278  bool const success = try_lease(pos, -1);
279  assert(success);
280  if (!success)
281  {
282  // TODO: anything to report? --mloskot
283  }
284 
285  return pos;
286 }
287 
288 bool connection_pool::try_lease(std::size_t & pos, int timeout)
289 {
290  DWORD cc = WaitForSingleObject(pimpl_->sem_,
291  timeout >= 0 ? static_cast<DWORD>(timeout) : INFINITE);
292  if (cc == WAIT_OBJECT_0)
293  {
294  // semaphore acquired, there is (at least) one free entry
295 
296  EnterCriticalSection(&(pimpl_->mtx_));
297 
298  bool const success = pimpl_->find_free(pos);
299  assert(success);
300  if (!success)
301  {
302  // TODO: anything to report? --mloskot
303  }
304 
305  pimpl_->sessions_[pos].first = false;
306 
307  LeaveCriticalSection(&(pimpl_->mtx_));
308 
309  return true;
310  }
311  else if (cc == WAIT_TIMEOUT)
312  {
313  return false;
314  }
315  else
316  {
317  throw soci_error("Synchronization error");
318  }
319 }
320 
321 void connection_pool::give_back(std::size_t pos)
322 {
323  if (pos >= pimpl_->sessions_.size())
324  {
325  throw soci_error("Invalid pool position");
326  }
327 
328  EnterCriticalSection(&(pimpl_->mtx_));
329 
330  if (pimpl_->sessions_[pos].first)
331  {
332  LeaveCriticalSection(&(pimpl_->mtx_));
333  throw soci_error("Cannot release pool entry (already free)");
334  }
335 
336  pimpl_->sessions_[pos].first = true;
337 
338  LeaveCriticalSection(&(pimpl_->mtx_));
339 
340  ReleaseSemaphore(pimpl_->sem_, 1, NULL);
341 }
342 
343 #endif // _WIN32
bool try_lease(std::size_t &pos, int timeout)
void give_back(std::size_t pos)
std::vector< std::pair< bool, session * > > sessions_
session & at(std::size_t pos)
connection_pool_impl * pimpl_
connection_pool(std::size_t size)


asr_lib_ism
Author(s): Hanselmann Fabian, Heller Florian, Heizmann Heinrich, Kübler Marcel, Mehlhaus Jonas, Meißner Pascal, Qattan Mohamad, Reckling Reno, Stroh Daniel
autogenerated on Wed Jan 8 2020 04:02:40