00001
00002
00003
00004 #ifndef DMLITE_CPP_UTILS_POOLCONTAINER_H
00005 #define DMLITE_CPP_UTILS_POOLCONTAINER_H
00006
00007 #include <boost/thread/mutex.hpp>
00008 #include <boost/thread/condition.hpp>
00009 #include <boost/date_time/posix_time/posix_time.hpp>
00010 #include <map>
00011 #include <syslog.h>
00012 #include <queue>
00013 #include "../exceptions.h"
00014
00015 namespace dmlite {
00016
00017
00018
00019 template <class E>
00020 class PoolElementFactory {
00021 public:
00022
00023 virtual ~PoolElementFactory() {};
00024
00025
00026 virtual E create() = 0;
00027
00028
00029 virtual void destroy(E) = 0;
00030
00031
00032 virtual bool isValid(E) = 0;
00033 };
00034
00035
00036
00037 template <class E>
00038 class PoolContainer {
00039 public:
00040
00041
00042
00043 PoolContainer(PoolElementFactory<E>* factory, int n): max_(n), factory_(factory), freeSlots_(2*n)
00044 {
00045 }
00046
00047
00048 ~PoolContainer()
00049 {
00050
00051 while (free_.size() > 0) {
00052 E e = free_.front();
00053 free_.pop_front();
00054 factory_->destroy(e);
00055 }
00056
00057
00058 if (used_.size() > 0) {
00059 syslog(LOG_USER | LOG_WARNING, "%ld used elements from a pool not released on destruction!", (long)used_.size());
00060 }
00061 }
00062
00063
00064 E acquire(bool block = true)
00065 {
00066 E e;
00067
00068 if (!block && (freeSlots_ == 0)) {
00069 throw DmException(DMLITE_SYSERR(EBUSY),
00070 std::string("No resources available"));
00071 }
00072
00073
00074 boost::system_time const timeout = boost::get_system_time() + boost::posix_time::seconds(60);
00075 boost::mutex::scoped_lock lock(mutex_);
00076 while (freeSlots_ < 1) {
00077 if (boost::get_system_time() >= timeout) {
00078 syslog(LOG_USER | LOG_WARNING, "Timeout...%d seconds", 60);
00079 break;
00080 }
00081 available_.timed_wait(lock, timeout);
00082 }
00083
00084
00085 if (free_.size() > 0) {
00086 e = free_.front();
00087 free_.pop_front();
00088
00089 if (!factory_->isValid(e)) {
00090 factory_->destroy(e);
00091 e = factory_->create();
00092 }
00093 }
00094 else {
00095
00096 e = factory_->create();
00097 }
00098
00099 used_.insert(std::pair<E, unsigned>(e, 1));
00100
00101
00102 --freeSlots_;
00103
00104 return e;
00105 }
00106
00107
00108 E acquire(E e)
00109 {
00110 boost::mutex::scoped_lock lock(mutex_);
00111
00112
00113 typename std::map<E, unsigned>::const_iterator i = used_.find(e);
00114 if (i == used_.end()) {
00115 throw DmException(DMLITE_SYSERR(EINVAL), std::string("The resource has not been locked previously!"));
00116 }
00117
00118
00119 used_[e]++;
00120
00121
00122 return e;
00123 }
00124
00125
00126
00127
00128 unsigned release(E e)
00129 {
00130 boost::mutex::scoped_lock lock(mutex_);
00131
00132 unsigned remaining = --used_[e];
00133
00134 if (used_[e] == 0) {
00135
00136 used_.erase(e);
00137
00138 if ((long)free_.size() < max_) {
00139 free_.push_back(e);
00140 }
00141 else {
00142
00143 factory_->destroy(e);
00144 }
00145 }
00146 available_.notify_one();
00147 ++freeSlots_;
00148
00149 return remaining;
00150 }
00151
00152
00153 unsigned refCount(E e)
00154 {
00155 typename std::map<E, unsigned>::const_iterator i = used_.find(e);
00156 if (i == used_.end())
00157 return 0;
00158 return used_[e];
00159 }
00160
00161
00162
00163 void resize(int ns)
00164 {
00165
00166 boost::mutex::scoped_lock lock(mutex_);
00167 max_ = ns;
00168
00169
00170 freeSlots_ = 2*max_ - used_.size();
00171
00172
00173 if (freeSlots_ > 0)
00174 available_.notify_all();
00175 }
00176
00177 private:
00178
00179 int max_;
00180
00181 PoolElementFactory<E> *factory_;
00182
00183 std::deque<E> free_;
00184 std::map<E, unsigned> used_;
00185 unsigned freeSlots_;
00186
00187 boost::mutex mutex_;
00188 boost::condition_variable available_;
00189 };
00190
00191
00192 template <class E>
00193 class PoolGrabber {
00194 public:
00195 PoolGrabber(PoolContainer<E>& pool, bool block = true): pool_(pool)
00196 {
00197 element_ = pool_.acquire(block);
00198 }
00199
00200 ~PoolGrabber() {
00201 pool_.release(element_);
00202 }
00203
00204 operator E ()
00205 {
00206 return element_;
00207 }
00208
00209 private:
00210 PoolContainer<E>& pool_;
00211 E element_;
00212 };
00213 };
00214
00215 #endif // DMLITE_CPP_UTILS_POOLCONTAINER_H