summaryrefslogtreecommitdiff
path: root/cpp/src/IceGrid/Allocatable.cpp
diff options
context:
space:
mode:
authorBenoit Foucher <benoit@zeroc.com>2006-04-27 16:06:50 +0000
committerBenoit Foucher <benoit@zeroc.com>2006-04-27 16:06:50 +0000
commitf4a0472080eb9f570d23892154093f057288c601 (patch)
tree788cd4e98d6963e2a27a3bcdaae6e01973788302 /cpp/src/IceGrid/Allocatable.cpp
parentdos2unix (diff)
downloadice-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.cpp371
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;
}
+