Added facilities for creating named locks on distributed objects that will

allow services to prevent repeated invocations of themselves from stepping
on one another because of the serial nature of event processing.


git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@171 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
Michael Bayne
2001-08-04 00:39:44 +00:00
parent 5d5b1cf0a4
commit 7873ee98f7
2 changed files with 117 additions and 10 deletions
@@ -1,5 +1,5 @@
//
// $Id: DObject.java,v 1.18 2001/08/03 02:11:40 mdb Exp $
// $Id: DObject.java,v 1.19 2001/08/04 00:39:44 mdb Exp $
package com.threerings.cocktail.cher.dobj;
@@ -129,6 +129,110 @@ public class DObject
}
}
/**
* At times, an entity on the server may need to ensure that events it
* has queued up have made it through the event queue and are applied
* to their respective objects before a service may safely be
* undertaken again. To make this possible, it can acquire a lock on a
* distributed object, generate the events in question and then
* release the lock (via a call to <code>releaseLock</code>) which
* will queue up a final event, the processing of which will release
* the lock. Thus the lock will not be released until all of the
* previously generated events have been processed. If the service is
* invoked again before that lock is released, the associated call to
* <code>acquireLock</code> will fail and the code can respond
* accordingly. An object may have any number of outstanding locks as
* long as they each have a unique name.
*
* @param name the name of the lock to acquire.
*
* @return true if the lock was acquired, false if the lock was not
* acquired because it has not yet been released from a previous
* acquisition.
*
* @see #releaseLock
*/
public boolean acquireLock (String name)
{
// create our lock array if we haven't already. we do all this
// jockeying rather than just use something like an ArrayList to
// be memory efficient because there may be very many distributed
// objects
if (_locks == null) {
_locks = new String[2];
}
// scan the lock array to see if this lock is already acquired
int slot = -1;
for (int i = 0; i < _locks.length; i++) {
if (_locks[i] == null) {
// keep track of this for later
slot = i;
} else if (name.equals(_locks[i])) {
return false;
}
}
// if we didnt' find a blank slot in our previous scan, we'll have
// to expand the locks array
if (slot == -1) {
String[] locks = new String[_locks.length*2];
System.arraycopy(_locks, 0, locks, 0, _locks.length);
slot = _locks.length;
}
// place our lock in the array and let the user know that they
// acquired the lock
_locks[slot] = name;
return true;
}
/**
* Queues up an event that when processed will release the lock of the
* specified name.
*
* @see #acquireLock
*/
public void releaseLock (String name)
{
// queue up a release lock event
ReleaseLockEvent event = new ReleaseLockEvent(_oid, name);
_mgr.postEvent(event);
}
/**
* Don't call this function! It is called by a remove lock event when
* that event is processed and shouldn't be called at any other time.
* If you mean to release a lock that was acquired with
* <code>acquireLock</code> you should be using
* <code>releaseLock</code>.
*
* @see #acquireLock
* @see #releaseLock
*/
protected void clearLock (String name)
{
// track the lock index for reporting purposes
int lockidx = -1;
// scan through and clear the lock in question
if (_locks != null) {
for (int i = 0; i < _locks.length; i++) {
if (name.equals(_locks[i])) {
_locks[i] = null;
lockidx = i;
break;
}
}
}
// complain if we didn't find the lock
if (lockidx == -1) {
Log.info("Unable to clear non-existent lock [lock=" + name +
", dobj=" + this + "].");
}
}
/**
* Checks to ensure that the specified subscriber has access to this
* object. This will be called before satisfying a subscription
@@ -304,4 +408,5 @@ public class DObject
protected int _oid;
protected DObjectManager _mgr;
protected ArrayList _subscribers = new ArrayList();
protected String[] _locks;
}
@@ -1,5 +1,5 @@
//
// $Id: ReleaseLockEvent.java,v 1.1 2001/08/04 00:32:11 mdb Exp $
// $Id: ReleaseLockEvent.java,v 1.2 2001/08/04 00:39:44 mdb Exp $
package com.threerings.cocktail.cher.dobj;
@@ -11,10 +11,13 @@ import java.lang.reflect.Method;
import com.threerings.cocktail.cher.dobj.io.ValueMarshaller;
/**
* A release lock event is dispatched at the end of a chain of attribute
* change events to release a lock that is intended to prevent some
* application defined activity from happening on the distributed object
* until those events have been processed.
* A release lock event is dispatched at the end of a chain of events to
* release a lock that is intended to prevent some application defined
* activity from happening until those events have been processed. This is
* an entirely cooperative locking system, meaning that the application
* will have to explicitly attempt acquisition of the lock to find out if
* the lock has yet been released. These locks don't actually prevent any
* of the distributed object machinery from functioning.
*
* @see DObjectManager#postEvent
*/
@@ -53,13 +56,13 @@ public class ReleaseLockEvent extends TypedEvent
}
/**
* Applies this attribute change to the object.
* Applies this lock release to the object.
*/
public boolean applyToObject (DObject target)
throws ObjectAccessException
{
// pass the new value on to the object
target.setAttribute(_name, _value);
// clear this lock from the target object
target.clearLock(_name);
return true;
}
@@ -90,5 +93,4 @@ public class ReleaseLockEvent extends TypedEvent
}
protected String _name;
protected Object _value;
}