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_(10*n)
00044 {
00045 }
00046
00047
00048 ~PoolContainer()
00049 {
00050 boost::mutex::scoped_lock lock(mutex_);
00051
00052 while (free_.size() > 0) {
00053 E e = free_.front();
00054 free_.pop_front();
00055 factory_->destroy(e);
00056 }
00057
00058
00059 if (used_.size() > 0) {
00060 syslog(LOG_USER | LOG_WARNING, "%ld used elements from a pool not released on destruction!", (long)used_.size());
00061 }
00062 }
00063
00064
00065 E acquire(bool block = true)
00066 {
00067 bool found = false;
00068 E e = {};
00069
00070 {
00071 boost::mutex::scoped_lock lock(mutex_);
00072
00073
00074 if (!block && (freeSlots_ <= 0)) {
00075 throw DmException(DMLITE_SYSERR(EBUSY),
00076 std::string("No resources available"));
00077 }
00078
00079 boost::system_time const timeout = boost::get_system_time() + boost::posix_time::seconds(1);
00080
00081 while (freeSlots_ < 1) {
00082 if (boost::get_system_time() >= timeout) {
00083 syslog(LOG_USER | LOG_WARNING, "Poolcontainer timeout. Size: %d free (can be negative): %d Stall: %d seconds in '%s'", max_, freeSlots_, 1, __PRETTY_FUNCTION__);
00084 break;
00085 }
00086 available_.timed_wait(lock, timeout);
00087 }
00088
00089
00090
00091 while (free_.size() > 0) {
00092 e = free_.front();
00093 free_.pop_front();
00094
00095
00096 if (!factory_->isValid(e)) {
00097 factory_->destroy(e);
00098 }
00099 else {
00100 found = true;
00101 break;
00102 }
00103 }
00104
00105 }
00106
00107
00108
00109 if (!found)
00110 e = factory_->create();
00111
00112 {
00113 boost::mutex::scoped_lock lock(mutex_);
00114
00115 used_.insert(std::pair<E, unsigned>(e, 1));
00116
00117
00118 --freeSlots_;
00119 }
00120 return e;
00121 }
00122
00123
00124 E acquire(E e)
00125 {
00126 boost::mutex::scoped_lock lock(mutex_);
00127
00128
00129 typename std::map<E, unsigned>::const_iterator i = used_.find(e);
00130 if (i == used_.end()) {
00131 throw DmException(DMLITE_SYSERR(EINVAL), std::string("The resource has not been locked previously!"));
00132 }
00133
00134
00135 used_[e]++;
00136
00137
00138 return e;
00139 }
00140
00141
00142
00143
00144 unsigned release(E e)
00145 {
00146 boost::mutex::scoped_lock lock(mutex_);
00147
00148 unsigned remaining = --used_[e];
00149
00150 if (used_[e] == 0) {
00151
00152 used_.erase(e);
00153
00154 if ((long)free_.size() < max_) {
00155 free_.push_back(e);
00156 }
00157 else {
00158
00159 factory_->destroy(e);
00160 }
00161 }
00162 available_.notify_one();
00163 ++freeSlots_;
00164
00165 return remaining;
00166 }
00167
00168
00169 unsigned refCount(E e)
00170 {
00171 typename std::map<E, unsigned>::const_iterator i = used_.find(e);
00172 if (i == used_.end())
00173 return 0;
00174 return used_[e];
00175 }
00176
00177
00178
00179 void resize(int ns)
00180 {
00181
00182 boost::mutex::scoped_lock lock(mutex_);
00183 max_ = ns;
00184
00185
00186 freeSlots_ = 10*max_ - used_.size();
00187
00188
00189 if (freeSlots_ > 0)
00190 available_.notify_all();
00191 }
00192
00193 private:
00194
00195 int max_;
00196
00197 PoolElementFactory<E> *factory_;
00198
00199 std::deque<E> free_;
00200 std::map<E, unsigned> used_;
00201 int freeSlots_;
00202
00203 boost::mutex mutex_;
00204 boost::condition_variable available_;
00205 };
00206
00207
00208 template <class E>
00209 class PoolGrabber {
00210 public:
00211 PoolGrabber(PoolContainer<E>& pool, bool block = true): pool_(pool)
00212 {
00213 element_ = pool_.acquire(block);
00214 }
00215
00216 ~PoolGrabber() {
00217 pool_.release(element_);
00218 }
00219
00220 operator E ()
00221 {
00222 return element_;
00223 }
00224
00225 private:
00226 PoolContainer<E>& pool_;
00227 E element_;
00228 };
00229 };
00230
00231 #endif // DMLITE_CPP_UTILS_POOLCONTAINER_H