#include #include "PassportObjectPool.hpp" #include "PassportSystem.hpp" #include "PassportGuard.hpp" //#include "PassportAssert.hpp" template int PassportObjectPool::smDefaultMinObjects = 1; template int PassportObjectPool::smDefaultMaxObjects = -1; // no max template long PassportObjectPool::smDefaultMaxSecondsInActive = 300; // 5 minutes /** * Constructor * * @param constructor the object that constructs objects * @param minObjects the minimum number of objects in the pool. * Negative is assumed to be zero * @param maxObjects the maximum objects in the pool. * Negative is assumed to unlimited number of objects * If maxObjects is less then minObjects then the maximum * number of objects will be equal to minObjects * @param maxSecondsInActive the maximum number of seconds that * an object that is not checked out is kept around. * Negative value assumes that objects once created will * never be released. (note: the number of objects will * never fall below minObjects even if they are not being used) */ template PassportObjectPool:: PassportObjectPool(int minObjects, int maxObjects, int maxSecondsInActive) :mMinObjects(minObjects), mMaxObjects(maxObjects), mMaxSecondsInActive(maxSecondsInActive), mLastInActivityCheck(PassportSystem::currentTimeInMillis()), mObjectConstructor(*new ObjectConstructor()), mOwnObjectConstructor(true) { growPoolToMinimum(); } /** * Constructor with object constructor * * @param objectConstructor is an instance of a class that has * a newObject object member function that returns a pointer to * an object of type PoolT * @param minObjects the minimum number of objects in the pool. * Negative is assumed to be zero * @param maxObjects the maximum objects in the pool. * Negative is assumed to unlimited number of objects * If maxObjects is less then minObjects then the maximum * number of objects will be equal to minObjects * @param maxSecondsInActive the maximum number of seconds that * an object that is not checked out is kept around. * Negative value assumes that objects once created will * never be released. (note: the number of objects will * never fall below minObjects even if they are not being used) */ template PassportObjectPool:: PassportObjectPool(ObjectConstructor& objectConstructor, int minObjects, int maxObjects, int maxSecondsInActive) :mMinObjects(minObjects), mMaxObjects(maxObjects), mMaxSecondsInActive(maxSecondsInActive), mLastInActivityCheck(PassportSystem::currentTimeInMillis()), mObjectConstructor(objectConstructor), mOwnObjectConstructor(false) { growPoolToMinimum(); } /** * Gets the min objects in the pool */ template int PassportObjectPool::getMinObjects() { PassportGuard guard(mLock); return mMinObjects; } /** * Sets the min objects in the pool * @param minObjects the minimum number of objects in the pool. * Negative is assumed to be zero. The minimum is greater * then the current maximum then the current maximum is * increased. */ template void PassportObjectPool::setMinObjects(int value) { PassportGuard guard(mLock); if (value < 0) mMinObjects = 0; else mMinObjects = value; if (mMinObjects > getMaxObjects()) setMaxObjects(mMinObjects); growPoolToMinimum(); } /** * Gets the max objects in the pool. Negative means * there is no maximum. */ template int PassportObjectPool::getMaxObjects() { PassportGuard guard(mLock); return mMaxObjects; } /** * Sets the max objects in the pool. Note because some objects * may be checked out this may not take effect immediately * @param maxObjects the maximum objects in the pool. * Negative is assumed to unlimited number of objects * If maxObjects is less then minObjects then the maximum * number of objects will be equal to minObjects */ template void PassportObjectPool::setMaxObjects(int value) { PassportGuard guard(mLock); if ((value >= 0) && (value < mMinObjects)) mMaxObjects = mMinObjects; else mMaxObjects = value; shrinkPoolToMaximum(); } /** * Gets the maximum no activity time for the pool. Negtive * means there is no maximum. */ template int PassportObjectPool::getMaxSecondsInActive() { PassportGuard guard(mLock); return mMaxSecondsInActive; } /** * Sets the maximum no activity time for the pool. * @param maxSecondsInActive the maximum number of seconds that * an object that is not checked out is kept around. * Negative value assumes that objects once created will * never be released. (note: the number of objects will * never fall below minObjects even if they are not being used) */ template void PassportObjectPool::setMaxSecondsInActive(int value) { PassportGuard guard(mLock); mMaxSecondsInActive = value; } /** * The object number of objects this pool is managing */ template int PassportObjectPool::totalObjects() { PassportGuard guard(mLock); return mAllObjects.size(); } /** * The total number of objects available to be checked * out */ template int PassportObjectPool::availableObjects() { PassportGuard guard(mLock); return mPooledObjects.size(); } /** * checks the object out of the pool */ template PoolT* PassportObjectPool::checkout() { PassportGuard guard(mLock); if ((availableObjects() == 0) && (roomToGrow())) growPool(); while (availableObjects() == 0) { mLock.wait(); } return getObjectFromTop(); } /** * checks the object back into the pool. The * object must be one that was retrieved using * checkout.and has not yet been checked in. * returns throws an assert if the object in being returned * was not generated by the pool or if the object * has already been checked in. */ template void PassportObjectPool::checkin(PoolT* object) { PassportGuard guard(mLock); // ------------------------ // return the object returnObjectToTop(object); // ------------------------------------ // we have to do this becauase the max // pool size could have changed. shrinkPoolToMaximum(); // ---------------------- // remove all old objects removeInActiveObjects(); // ---------------------- // notify anyone that is // waiting that an object // has been returned. mLock.notify(); } /** * This functions call the modify * functions on the modifier for * every function in the pool. * NOTE: that the objects in the pool * are responsible for locking themselves * because this method could get call while * another thread is using a checked out * pooled object. */ /*template void PassportObjectPool::modifyPooledObjects(PassportModifier& modifier) { PassportGuard guard(mLock); for (int i = 0 ; i < totalObjects() ; i++ ) { modifier.modify(mAllObjects[i]); } } */ /* * NOTE: all objects better be returned before this is called */ template PassportObjectPool::~PassportObjectPool() { //PassportAssert(totalObjects() == availableObjects()); while (totalObjects() != 0) { removeOldestObject(); } if (mOwnObjectConstructor) delete &mObjectConstructor; } template bool PassportObjectPool::roomToGrow() { PassportGuard guard(mLock); return ((getMaxObjects() < 0) || (getMaxObjects() > totalObjects())); } template PoolT* PassportObjectPool::getObjectFromTop() { PassportGuard guard(mLock); // --------------------------- // remove it internal list mInActiveTimes.pop_back(); // ------------------------- // get the top object PoolT* obj = mPooledObjects.back(); mPooledObjects.pop_back(); return obj; } template bool PassportObjectPool::contains(const std::list& vec, PoolT* obj) { return (std::find(vec.begin(),vec.end(), obj) != vec.end()); } template bool PassportObjectPool::contains(const std::deque& vec, PoolT* obj) { return (std::find(vec.begin(),vec.end(), obj) != vec.end()); } template void PassportObjectPool::returnObjectToTop(PoolT* obj) { PassportGuard guard(mLock); // ---------------------------- // check if this object was // generated by the pool. //PassportAssert(contains(mAllObjects, obj)); // -------------------------------- // check if this object has already // been returned. //PassportAssert(!contains(mPooledObjects,obj)); // ----------------------------- // add it to pooled objects list mPooledObjects.push_back(obj); // ---------------------- // set the inactive time mInActiveTimes.push_back(PassportSystem::currentTimeInMillis()); } template void PassportObjectPool::growPoolToMinimum() { PassportGuard guard(mLock); // -------------------- // grow the pool until // it is big enough while (totalObjects() < getMinObjects()) growPool(); } template void PassportObjectPool::growPool() { PassportGuard guard(mLock); /* fix if (smDebug) cout << "Growing Pool to " << (totalObjects()+1) << " objects" << endl; */ // --------------------------- // construct a new object PoolT* obj = mObjectConstructor.newObject(); // ------------------------------- // add it to the vector of objects mPooledObjects.push_back(obj); // --------------------------------------- // add a field to store the objects // last use time mInActiveTimes.push_back(PassportSystem::currentTimeInMillis()); // --------------------------- // add the object to the list // of all objects. mAllObjects.push_back(obj); } template void PassportObjectPool::shrinkPoolToMaximum() { PassportGuard guard(mLock); while ((getMaxObjects() >= 0) && (getMaxObjects() < totalObjects()) && (availableObjects() > 0)) { /* fix if (smDebug) cout << "Removing object because the maximum number of " << "objects allowed has decresed" << endl; */ removeOldestObject(); } } template void PassportObjectPool::removeInActiveObjects() { PassportGuard guard(mLock); // --------------------------------- // negative maxSecondsInActive indicates // to never in activate objects. We also // only check for in active objects // every once in a while. finally // we should not remove any objects // if we are already at the minimum long now = PassportSystem::currentTimeInMillis(); if ((mMaxSecondsInActive < 0) || (mLastInActivityCheck + 1000*mMaxSecondsInActive/2 > now) || (totalObjects() == getMinObjects())) return; mLastInActivityCheck = now; /* fix if (smDebug) cout << "Checking for inactive objects" << endl; */ // ------------------------------------------------------- // since the inactive times list goes from most // least often used to most often used we can stop looking // as soon as we find an object that has not expired. while ((totalObjects() > getMinObjects()) && (oldestObjectExpired())) { /* fix if (smDebug) cout << "Removing object because it has expired. Shrinking pool to " << totalObjects() - 1 << " objects" << endl; */ removeOldestObject(); } } template bool PassportObjectPool::oldestObjectExpired() { PassportGuard guard(mLock); return (mLastInActivityCheck - mInActiveTimes[0] > 1000*mMaxSecondsInActive); } template void PassportObjectPool::removeOldestObject() { PassportGuard guard(mLock); //----------------------------- // get the object to be removed PoolT* obj = mPooledObjects.front(); // -------------------------------------- // remove it from the list of all objects removeElement(mAllObjects, obj); // ------------------------------------ // remove it from the vector of objects mPooledObjects.pop_front(); // ------------------------ // remove the inactive time mInActiveTimes.pop_front(); // ------------------ // delete the object. delete obj; } template void PassportObjectPool::removeElement(std::list& vec, PoolT* obj) { std::list::iterator i = std::find(vec.begin(), vec.end(), obj); //PassportAssert(i != vec.end()); vec.erase(i); } template bool PassportObjectPool::smDebug = true;