00001
00002
00003
00004 #ifndef DMLITE_CPP_UTILS_POOLCONTAINER_H
00005 #define DMLITE_CPP_UTILS_POOLCONTAINER_H
00006
00007 #include <errno.h>
00008 #include <map>
00009 #include <pthread.h>
00010 #include <semaphore.h>
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)
00044 {
00045 pthread_mutex_init(&mutex_, NULL);
00046 sem_init(&available_, 0, n);
00047 }
00048
00049
00050 ~PoolContainer()
00051 {
00052
00053 while (free_.size() > 0) {
00054 E e = free_.front();
00055 free_.pop();
00056 factory_->destroy(e);
00057 }
00058
00059
00060 if (used_.size() > 0) {
00061 syslog(LOG_USER | LOG_WARNING, "%ld used elements from a pool not released on destruction!", (long)used_.size());
00062 }
00063
00064 pthread_mutex_destroy(&mutex_);
00065 sem_destroy(&available_);
00066 }
00067
00068
00069 E acquire(bool block = true)
00070 {
00071 E e;
00072
00073 if (!block) {
00074 int v;
00075 sem_getvalue(&available_, &v);
00076 if (v <= 0)
00077 throw DmException(DM_RESOURCE_UNAVAILABLE, std::string("No resources available"));
00078 }
00079 sem_wait(&available_);
00080
00081 pthread_mutex_lock(&mutex_);
00082
00083 if (free_.size() > 0) {
00084 e = free_.front();
00085 free_.pop();
00086
00087 if (!factory_->isValid(e)) {
00088 factory_->destroy(e);
00089 e = factory_->create();
00090 }
00091 }
00092 else {
00093
00094 e = factory_->create();
00095 }
00096
00097 used_.insert(std::pair<E, unsigned>(e, 1));
00098
00099 pthread_mutex_unlock(&mutex_);
00100 return e;
00101 }
00102
00103
00104 E acquire(E e)
00105 {
00106
00107 pthread_mutex_lock(&mutex_);
00108
00109
00110 typename std::map<E, unsigned>::const_iterator i = used_.find(e);
00111 if (i == used_.end())
00112 throw DmException(DM_INVALID_VALUE, std::string("The resource has not been locked previously!"));
00113
00114
00115 used_[e]++;
00116
00117
00118 pthread_mutex_unlock(&mutex_);
00119 return e;
00120 }
00121
00122
00123
00124
00125 unsigned release(E e)
00126 {
00127
00128 pthread_mutex_lock(&mutex_);
00129
00130 unsigned remaining = --used_[e];
00131
00132 if (used_[e] == 0) {
00133
00134 used_.erase(e);
00135
00136 if ((long)free_.size() < max_) {
00137 free_.push(e);
00138 sem_post(&available_);
00139 }
00140 else {
00141
00142 factory_->destroy(e);
00143 }
00144 }
00145
00146 pthread_mutex_unlock(&mutex_);
00147
00148 return remaining;
00149 }
00150
00151
00152 unsigned refCount(E e)
00153 {
00154 typename std::map<E, unsigned>::const_iterator i = used_.find(e);
00155 if (i == used_.end())
00156 return 0;
00157 return used_[e];
00158 }
00159
00160
00161
00162 void resize(int ns)
00163 {
00164 int total, sv;
00165
00166 pthread_mutex_lock(&mutex_);
00167 max_ = ns;
00168
00169
00170 sem_getvalue(&available_, &sv);
00171 while (sv > max_) {
00172 sem_wait(&available_);
00173 --sv;
00174 }
00175
00176
00177 total = sv + used_.size();
00178 while (total < max_) {
00179 sem_post(&available_);
00180 ++total;
00181 }
00182
00183 pthread_mutex_unlock(&mutex_);
00184 }
00185
00186 private:
00187 int max_;
00188
00189 PoolElementFactory<E> *factory_;
00190
00191 std::queue<E> free_;
00192 std::map<E, unsigned> used_;
00193
00194 pthread_mutex_t mutex_;
00195 sem_t available_;
00196 };
00197
00198 };
00199
00200 #endif // DMLITE_CPP_UTILS_POOLCONTAINER_H