Nevelex Corporation Nevelex Utilities 1.1.4 09/06/2003
Main Page   Namespace List   Class Hierarchy   Compound List   File List   Namespace Members   Compound Members   Related Pages  

ObjectPool.h

00001 
00031 /***************************************************************************
00032         ObjectPool.h  -  Template class used to as the basis for object pooling.
00033                              -------------------
00034         Author:         Michel Dalal
00035         Date:           Mon Sep 23 2002
00036         Copyright:      (C) 2002 Nevelex Corporation
00037  ***************************************************************************/
00038 
00039 #ifndef OBJECTPOOL_H
00040 #define OBJECTPOOL_H
00041 
00042 #include <deque>
00043 #if defined(__GNUG__) && (__GNUG__ >= 3)
00044 #include <ext/hash_set>
00045 #else
00046 #include <hash_set>
00047 #endif
00048 #include <iterator>
00049 #include <stdexcept>
00050 #include <time.h>
00051 #include "ace/Synch.h"
00052 #include "PointerHash.h"
00053 #include "ObjectPoolManager.h"
00054 
00062 namespace nevelex_util
00063 {
00092     template <class T>
00093         class ObjectPool: public ManagedPool
00094         {
00095         private:
00097                 ACE_Thread_Mutex mutex;
00098                 
00100                 time_t expiresTime;
00101 
00107                 typedef std::deque<T*> UnlockedDeque;
00108 
00114                 typedef std::deque<time_t> UnlockedCheckInDeque;
00115 
00120                 typedef HASH_NAMESPACE::hash_set<T*, PointerHash<T*> > LockedSet;
00121 
00125                 UnlockedDeque unlocked;
00126 
00130                 UnlockedCheckInDeque unlockedCheckInTimes;
00131 
00135                 LockedSet locked;
00136 
00146                 inline T* createElement()
00147                 {
00148                         T* t;
00149 
00150                         // Create a new t object.
00151                         t = new T();
00152                         if (t == NULL)
00153                         {
00154                                 throw std::runtime_error("Unable to create new object.");
00155                         }
00156                         return t;                       
00157                 }
00158                 
00165                 void insertElement(T* t)
00166                 {
00167                         time_t checkInTime;
00168 
00169                         // Get the time.
00170                         checkInTime=time(NULL);
00171                         assert(checkInTime != ((time_t)-1));
00172 
00173                         // Check in the object in to the unlocked deques.
00174                         unlockedCheckInTimes.push_back(checkInTime);
00175                         unlocked.push_back(t);
00176                         
00177 #ifdef _DEBUG_LOWLEVEL
00178                         cerr << "insertElement(): unlocked.size() = " << unlocked.size() << "; unlockedCheckInTimes.size() = " << unlockedCheckInTimes.size() << "\n";
00179 #endif
00180                 }
00181 
00190                 void addElement()
00191                 {
00192                         T* t;
00193 
00194                         // Create a new t object.
00195                         t = createElement();
00196 
00197                         // Add the object to the pool.
00198                         insertElement(t);
00199                 }
00200 
00201         public:
00208                 ObjectPool(time_t expiresTime):
00209                         mutex(),expiresTime(expiresTime)
00210                 {
00211                         // Add this object to the ObjectPoolManager for automatic cleanUps.
00212                         ObjectPoolManager::addPool(this);
00213                 }
00214 
00219                 virtual ~ObjectPool()
00220                 {
00221                         T* t;
00222 
00223                         // Remove this object from the ObjectPoolManager.
00224                         ObjectPoolManager::removePool(this);
00225 
00226                         while (!locked.empty())
00227                         {
00228                                 t = *(locked.begin());
00229                                 locked.erase(t);
00230                                 delete t;
00231                         }
00232                         while (!unlocked.empty())
00233                         {
00234                                 delete unlocked[0];
00235                                 unlocked.pop_front();
00236                         }
00237                         //unlocked.clear();
00238                         unlockedCheckInTimes.clear();
00239                 }
00240 
00246                 ObjectPool(const ObjectPool<T>& m)
00247                 {
00248                         expiresTime = m.expiresTime;
00249                         unlocked = m.unlocked;
00250                         unlockedCheckInTimes = m.unlockedCheckInTimes;
00251                         locked = m.locked;
00252                 }
00253 
00259                 const ObjectPool<T>& operator=(const ObjectPool<T>& rhs)
00260                 {
00261                         // Prevent self assignment
00262                         if (&rhs != this)
00263                         {
00264                                 expiresTime=rhs.expiresTime;
00265                                 unlocked=rhs.unlocked;
00266                                 unlockedCheckInTimes = rhs.unlockedCheckInTimes;
00267                                 locked=rhs.locked;
00268                         }
00269                         return *this;
00270                 }
00271 
00281                 T* checkOut(void)
00282                 {
00283                         T* t;
00284 
00285                         ACE_Guard<ACE_Thread_Mutex> guard(mutex);
00286                         {
00287                                 // Entered critical section.
00288 
00289                                 // Add an element to the unlocked pool if needed.
00290                                 if (unlocked.empty())
00291                                 {
00292                                         addElement();
00293                                 }
00294 
00295                                 // Lock the element.
00296                                 t = unlocked[0];
00297                                 locked.insert(t);
00298                                 assert(locked.find(t) != locked.end());
00299                                 unlocked.erase(unlocked.begin());
00300                                 unlockedCheckInTimes.erase(unlockedCheckInTimes.begin());
00301                                 //assert(unlocked.find(t) == unlocked.end());
00302                         }       // Leaving critical section
00303 
00304                         // return the object.
00305                         return t;
00306                 }
00307 
00319                 inline T* checkOutFast(void)
00320                 {
00321                         // return the object.
00322                         return createElement();
00323                 }
00324 
00334                 void checkIn(T* object)
00335                 {
00336                         LockedSet::iterator iterator;
00337 
00338                         ACE_Guard<ACE_Thread_Mutex> guard(mutex);
00339                         {
00340                                 // Entered critical section.
00341 
00342                                 if ((iterator = locked.find(object)) != locked.end())
00343                                 {
00344                                         // Add element to the unlocked list.
00345                                         insertElement(object);
00346 
00347                                         // Remove from the locked list.
00348                                         locked.erase(iterator);
00349                                         assert(locked.find(object) == locked.end());
00350                                 }
00351                                 else
00352                                 {
00353                                         throw std::runtime_error("Unable to checkIn object.");
00354                                 }
00355                         }       // Leaving critical section
00356                 }
00357 
00368                 inline void checkInFast(T* t)
00369                 {
00370                         // return the object.
00371                         delete t;
00372                 }
00373 
00383                 void cleanUp()
00384                 {
00385                         time_t currentTime;
00386 
00387                         ACE_Guard<ACE_Thread_Mutex> guard(mutex);
00388                         {
00389                                 // Entered critical section.
00390 
00391                                 // Get the current time.
00392                                 currentTime = time(NULL);
00393                                 assert(currentTime != ((time_t) -1));
00394 
00395 #ifdef _DEBUG_LOWLEVEL
00396                                 cerr << "cleanUp(): Starting: unlocked.size() = " << unlocked.size() << "\n";
00397 #endif
00398                                 // Remove all unneeded objects from the pool.
00399                                 // An object is unneeded if it has been checked in for longer than
00400                                 // expiresTime seconds.
00401                                 while (!unlockedCheckInTimes.empty() && currentTime - unlockedCheckInTimes[0] > expiresTime)
00402                                 {
00403 #ifdef _DEBUG_LOWLEVEL
00404                                         cerr << "cleanUp(): Removing Key = " << unlocked[0] << "; Elapsed Time Since checkIn = " << (currentTime - unlockedCheckInTimes[0]) << "\n";
00405 #endif
00406                                         // Free up the memory associated with the object being erased from the pool
00407                                         delete unlocked[0];
00408                                         
00409                                         unlocked.pop_front();
00410                                         unlockedCheckInTimes.erase(unlockedCheckInTimes.begin());
00411 #ifdef _DEBUG_LOWLEVEL
00412                                         cerr << "cleanUp(): unlocked.size() = " << unlocked.size() << "; unlockedCheckInTimes.size() = " << unlockedCheckInTimes.size() << "\n";
00413 #endif
00414                                 }
00415 #ifdef _DEBUG_LOWLEVEL
00416                                 cerr << "cleanUp(): Ending: unlocked.size() = " << unlocked.size() << "\n";
00417 #endif
00418                         }       // Leaving critical section
00419                 }
00420 
00421 #ifdef _DEBUG
00422 
00430                 void debugTest(size_t totalNum, size_t unlockedNum)
00431                 {
00432                         LockedSet::iterator iterator1;
00433                         size_t i;
00434 
00435                         ACE_Guard<ACE_Thread_Mutex> guard(mutex);
00436                         {
00437                                 // Entered critical section.
00438 
00439                                 cerr << "===================================================================\n";
00440                                 cerr << "Dumping Pool State...\n";
00441                                 cerr << "\tExpecting: Total of " << totalNum << ": Unlocked = " << unlockedNum << "; Locked = " << totalNum-unlockedNum << "\n";
00442                                 if (unlocked.empty())
00443                                 {
00444                                         cerr << " - unlocked: empty\n";
00445                                 }
00446                                 else
00447                                 {
00448                                         cerr << " - unlocked: size = " << unlocked.size() << "\n";
00449                                         for (i = 0; i < unlocked.size(); ++i)
00450                                         {
00451                                                 cerr << "\tKey = " << unlocked[i] << "; Elapsed Time Since checkIn = " << time(NULL) - unlockedCheckInTimes[i] << "\n";
00452                                         }
00453                                         //std::copy(unlocked.begin(), unlocked.end(), ostream_iterator<T>(cerr, "\n"));
00454                                 }
00455                         
00456                                 if (locked.empty())
00457                                 {
00458                                         cerr << " - locked: empty" << "\n";
00459                                 }
00460                                 else
00461                                 {
00462                                         cerr << " - locked: size = " << locked.size() << "\n";
00463                                         for (iterator1 = locked.begin(); iterator1 != locked.end(); iterator1++)
00464                                         {
00465                                                 cerr << "\t" << *iterator1 << "\n";
00466                                         }
00467                                         //std::copy(locked.begin(), locked.end(), ostream_iterator<T>(cerr, "\n"));
00468                                 }
00469 
00470                                 // Throw exceptions on unexpected results.
00471                                 if (totalNum != locked.size() + unlocked.size())
00472                                 {
00473                                         throw std::runtime_error("Total size does not match.");
00474                                 }
00475                                 if (unlockedNum != unlocked.size())
00476                                 {
00477                                         throw std::runtime_error("Unlocked size does not match.");
00478                                 }
00479                                 if (totalNum - unlockedNum != locked.size())
00480                                 {
00481                                         throw std::runtime_error("Locked size does not match.");
00482                                 }
00483                         }       // Leaving critical section
00484                 }
00485 #endif
00486     };
00487 }       // namespace nevelex_util
00488 #endif