diff options
author | Benoit Foucher <benoit@zeroc.com> | 2006-04-27 16:06:50 +0000 |
---|---|---|
committer | Benoit Foucher <benoit@zeroc.com> | 2006-04-27 16:06:50 +0000 |
commit | f4a0472080eb9f570d23892154093f057288c601 (patch) | |
tree | 788cd4e98d6963e2a27a3bcdaae6e01973788302 /cpp/src/IceGrid/Allocatable.cpp | |
parent | dos2unix (diff) | |
download | ice-f4a0472080eb9f570d23892154093f057288c601.tar.bz2 ice-f4a0472080eb9f570d23892154093f057288c601.tar.xz ice-f4a0472080eb9f570d23892154093f057288c601.zip |
More work on allocation.
Diffstat (limited to 'cpp/src/IceGrid/Allocatable.cpp')
-rw-r--r-- | cpp/src/IceGrid/Allocatable.cpp | 371 |
1 files changed, 241 insertions, 130 deletions
diff --git a/cpp/src/IceGrid/Allocatable.cpp b/cpp/src/IceGrid/Allocatable.cpp index 510663cf9ca..a5f8419fad8 100644 --- a/cpp/src/IceGrid/Allocatable.cpp +++ b/cpp/src/IceGrid/Allocatable.cpp @@ -18,10 +18,29 @@ AllocationRequest::~AllocationRequest() } bool -AllocationRequest::setAllocatable(const AllocatablePtr& allocatable) +AllocationRequest::pending() { - assert(allocatable); + Lock sync(*this); + assert(_state == Initial); + + if(_timeout == 0) + { + _state = Canceled; + canceled(AllocationTimeoutException()); + return false; + } + else if(_timeout > 0) + { + _session->getWaitQueue()->add(this, IceUtil::Time::milliSeconds(_timeout)); + } + _state = Pending; + _session->addAllocationRequest(this); + return true; +} +bool +AllocationRequest::finish(const AllocatablePtr& allocatable) +{ Lock sync(*this); switch(_state) { @@ -34,56 +53,54 @@ AllocationRequest::setAllocatable(const AllocatablePtr& allocatable) { _session->getWaitQueue()->remove(this); } + _session->removeAllocationRequest(this); break; case Allocated: assert(false); break; } - _allocatable = allocatable; - _state = Allocated; - allocated(_allocatable); - return true; + // + // Check if the allocatable is already allocated by the session + // and if it's allowed to allocate multiple times the same + // allocatable. + // + if(allocateOnce() && _session == allocatable->getSession()) + { + _state = Canceled; + canceled(AllocationException("already allocated by the session")); + return false; + } + else + { + _state = Allocated; + allocated(allocatable); + return true; + } } void -AllocationRequest::cancel() +AllocationRequest::cancel(const AllocationException& ex) { - AllocatablePtr allocatable; + Lock sync(*this); + switch(_state) { - Lock sync(*this); - switch(_state) + case Initial: + break; + case Canceled: + case Allocated: + return; + case Pending: + if(_timeout > 0) { - case Initial: - assert(false); - case Canceled: - return; - case Pending: - if(_timeout > 0) - { - _session->getWaitQueue()->remove(this); - } - canceled(); - break; - case Allocated: - allocatable = _allocatable; - break; + _session->getWaitQueue()->remove(this); } - - _state = Canceled; - } + _session->removeAllocationRequest(this); + break; + } - if(allocatable) - { - try - { - allocatable->release(_session); - } - catch(const AllocationException&) - { - // Ignore, the allocatable might already have been released. - } - } + _state = Canceled; + canceled(ex); } void @@ -95,38 +112,15 @@ AllocationRequest::expired(bool destroyed) case Initial: assert(false); case Canceled: + case Allocated: return; case Pending: - timeout(); + _session->removeAllocationRequest(this); break; - case Allocated: - return; } _state = Canceled; -} - -void -AllocationRequest::allocate() -{ - _session->addAllocationRequest(this); - - Lock sync(*this); - assert(_allocatable || _state == Initial); - if(!_allocatable) - { - if(_timeout > 0) - { - _session->getWaitQueue()->add(this, IceUtil::Time::milliSeconds(_timeout)); - } - _state = Pending; - } -} - -void -AllocationRequest::release() -{ - _session->removeAllocationRequest(this); + canceled(AllocationTimeoutException()); } bool @@ -142,114 +136,231 @@ AllocationRequest::AllocationRequest(const SessionIPtr& session) : { } -Allocatable::Allocatable(bool allocatable) : _allocatable(allocatable), _allocated(false) +ParentAllocationRequest::ParentAllocationRequest(const AllocationRequestPtr& request, + const AllocatablePtr& allocatable) : + AllocationRequest(request->getSession()), + _request(request), + _allocatable(allocatable) { } -Allocatable::~Allocatable() +void +ParentAllocationRequest::allocated(const AllocatablePtr& allocatable) { + try + { + _allocatable->allocate(_request, false); + assert(_allocatable->getSession() == _request->getSession()); + } + catch(const AllocationException& ex) + { + _request->cancel(ex); + } } void -Allocatable::allocate(const AllocationRequestPtr& request, bool once) +ParentAllocationRequest::canceled(const AllocationException& ex) +{ + _request->canceled(ex); +} + +Allocatable::Allocatable() : _allocatable(false), _count(0) +{ +} + +Allocatable::~Allocatable() +{ +} + +void +Allocatable::allocate(const AllocationRequestPtr& request, bool checkParent) { - IceUtil::Mutex::Lock sync(_allocateMutex); - if(_allocatable) + IceUtil::RecMutex::Lock sync(_allocateMutex); + if(!_allocatable) + { + throw NotAllocatableException("not allocatable"); + } + + if(_session == request->getSession()) { - if(_allocated) + if(request->finish(this)) { - if(_allocated->getSession() == request->getSession()) - { - if(once) - { - throw AllocationException("object already allocated by the session"); - } - else - { - request->setAllocatable(this); - } - } - else if(request->getTimeout()) - { - request->allocate(); - _requests.push_back(request); // TODO: XXX: monitor request timeout if timeout != -1 - } - else - { - request->timeout(); - } + ++_count; } - else if(request->setAllocatable(this)) + return; + } + + if(_parent && checkParent) + { + _parent->allocate(new ParentAllocationRequest(request, this), true); + return; + } + + if(_session) + { + if(request->pending()) { - _allocated = request; - _allocated->allocate(); - allocated(); + _requests.push_back(request); } + } + else if(request->finish(this)) + { + assert(_count == 0); + _session = request->getSession(); + ++_count; + allocated(_session); } - else +} + +bool +Allocatable::tryAllocateWithSession(const SessionIPtr& session, const AllocatablePtr& child) +{ + IceUtil::RecMutex::Lock sync(_allocateMutex); + assert(_allocatable); + if(_session && _session != session) + { + _attempts.insert(child); // Remember the allocation attempts of a child + return false; + } + else if(_session == session) { - throw AllocationException("can't allocate non allocatable object"); + ++_count; + return true; + } + + if(_parent && !_parent->tryAllocateWithSession(session, child)) + { + return false; } + + assert(_count == 0); + + _session = session; + ++_count; + allocated(_session); + return true; } bool Allocatable::tryAllocate(const AllocationRequestPtr& request) { - IceUtil::Mutex::Lock sync(_allocateMutex); - if(_allocatable) + IceUtil::RecMutex::Lock sync(_allocateMutex); + + // + // If not allocatable or already allocated or if the parent is + // allocated by a session other than the session from the given + // request, we can't allocate the allocatable. + // + if(!_allocatable || _session) { - if(_allocated) - { - if(_allocated->getSession() == request->getSession()) - { - throw AllocationException("object already allocated by the session"); - } - return false; - } - else if(request->setAllocatable(this)) - { - _allocated = request; - _allocated->allocate(); - allocated(); - } - return true; // The allocatable was allocated or the request was canceled. + return false; } - else + + if(_parent && !_parent->tryAllocateWithSession(request->getSession(), this)) { return false; } + + if(request->finish(this)) + { + assert(_count == 0); + _session = request->getSession(); + ++_count; + allocated(_session); + } + return true; // The allocatable was allocated or the request was canceled. +} + +bool +Allocatable::release(const SessionIPtr&) +{ + assert(false); } bool -Allocatable::release(const SessionIPtr& session) +Allocatable::release(const SessionIPtr& session, bool all, set<AllocatablePtr>& releasedAllocatables) { - IceUtil::Mutex::Lock sync(_allocateMutex); - if(!_allocated || _allocated->getSession() != session) + IceUtil::RecMutex::Lock sync(_allocateMutex); + if(!_session || _session != session) { throw AllocationException("can't release object which is not allocated"); } - _allocated->release(); + if(!all && --_count) + { + return false; + } + _session = 0; + _count = 0; - // - // Allocate the allocatable to another client. - // - while(!_requests.empty()) + released(session); + + if(_parent) + { + assert(_requests.empty()); + _parent->release(session, false, releasedAllocatables); + } + else { - _allocated = _requests.front(); - _requests.pop_front(); - if(_allocated->setAllocatable(this)) + // + // Allocate the allocatable to another session. + // + while(!_requests.empty()) { - return false; + AllocationRequestPtr request = _requests.front(); + _requests.pop_front(); + if(request->finish(this)) + { + _session = request->getSession(); + ++_count; + allocated(_session); + + // + // Check if there's other requests from the session + // waiting to allocate this allocatable. + // + list<AllocationRequestPtr>::iterator p = _requests.begin(); + while(p != _requests.end()) + { + if((*p)->getSession() == _session) + { + if((*p)->finish(this)) + { + ++_count; + } + p = _requests.erase(p); + } + else + { + ++p; + } + } + return false; + } } } - released(); - _allocated = 0; + + releasedAllocatables.insert(_attempts.begin(), _attempts.end()); + _attempts.clear(); return true; } bool Allocatable::isAllocated() const { - IceUtil::Mutex::Lock sync(_allocateMutex); - return _allocated; + IceUtil::RecMutex::Lock sync(_allocateMutex); + return _session || _parent && _parent->isAllocated(); +} + +SessionIPtr +Allocatable::getSession() const +{ + IceUtil::RecMutex::Lock sync(_allocateMutex); + return _session; +} + +bool +Allocatable::operator<(const Allocatable& r) const +{ + return this < &r; } + |