diff options
Diffstat (limited to 'libjava/classpath/gnu/java/rmi/dgc')
-rw-r--r-- | libjava/classpath/gnu/java/rmi/dgc/DGCImpl.java | 152 | ||||
-rw-r--r-- | libjava/classpath/gnu/java/rmi/dgc/LeaseRenewingTask.java | 234 |
2 files changed, 304 insertions, 82 deletions
diff --git a/libjava/classpath/gnu/java/rmi/dgc/DGCImpl.java b/libjava/classpath/gnu/java/rmi/dgc/DGCImpl.java index a7bc0940ed0..a5c036e7b6f 100644 --- a/libjava/classpath/gnu/java/rmi/dgc/DGCImpl.java +++ b/libjava/classpath/gnu/java/rmi/dgc/DGCImpl.java @@ -38,6 +38,7 @@ exception statement from your version. */ package gnu.java.rmi.dgc; +import gnu.java.rmi.server.UnicastServer; import gnu.java.rmi.server.UnicastServerRef; import java.rmi.RemoteException; @@ -46,7 +47,8 @@ import java.rmi.dgc.Lease; import java.rmi.dgc.VMID; import java.rmi.server.ObjID; import java.rmi.server.RMISocketFactory; -import java.util.Hashtable; +import java.util.Collection; +import java.util.TimerTask; /** * The DGC implementation is used for the server side during the distributed @@ -68,14 +70,67 @@ public class DGCImpl */ /** + * Use the serial version UID for interoperability. + */ + private static final long serialVersionUID = 1; + + /** + * Protects the array of object Id's for the scheduled period of time + * (lease). After the time expires, the protector is automatically discarded, + * making the references unprotected and hence applicable for the garbage + * collection. + */ + class RefProtector extends TimerTask + { + /** + * The corresponding server references to protect. Each Id may contain + * multiple references that are stored to collection. + */ + Collection[] references; + + /** + * Create the new instance of the reference protector that protects the + * given array of ids and exists for the given period of time. + * + * @param ids the ids to protect. + */ + RefProtector(ObjID[] ids, long timeToLive) + { + references = new Collection[ids.length]; + for (int i = 0; i < ids.length; i++) + { + references[i] = UnicastServer.getExported(ids[i]); + } + + // Schedule the existence. + LeaseRenewingTask.timer.schedule(this, timeToLive); + } + + /** + * Break all links, ensuring easy collection of the references by the gc. + */ + public void run() + { + for (int i = 0; i < references.length; i++) + { + references[i].clear(); + references[i] = null; + } + } + } + + /** * This defauld lease value is used if the lease value, passed to the * {@link #dirty} is equal to zero. */ static final long LEASE_VALUE = 600000L; - - // leaseCache caches a LeaseRecord associated with a vmid - Hashtable leaseCache = new Hashtable(); - + + /** + * Create the new DGC implementation. + * + * @throws RemoteException if the super constructor throws or the + * socket factory fails. + */ public DGCImpl() throws RemoteException { super(new ObjID(ObjID.DGC_ID), 0, RMISocketFactory.getSocketFactory()); @@ -92,26 +147,20 @@ public class DGCImpl */ public Lease dirty(ObjID[] ids, long sequenceNum, Lease lease) throws RemoteException - { - VMID vmid = lease.getVMID(); - if (vmid == null) - vmid = new VMID(); - + { + // We do not fill in VMID because in this implementation it is not used. long leaseValue = lease.getValue(); + + // Grant the maximal default lease time if the passed value is zero. if (leaseValue <= 0) leaseValue = LEASE_VALUE; - - lease = new Lease(vmid, leaseValue); - LeaseRecord lr = (LeaseRecord) leaseCache.get(vmid); - if (lr != null) - lr.reset(leaseValue); - else - { - lr = new LeaseRecord(vmid, leaseValue, ids); - leaseCache.put(vmid, lr); - } - return (lease); + // Create (and shedule of the given existence) the new reference + // protector. + new RefProtector(ids, leaseValue); + + lease = new Lease(lease.getVMID(), leaseValue); + return lease; } /** @@ -130,65 +179,4 @@ public class DGCImpl // TODO implement } - /** - * LeaseRecord associates a vmid to expireTime. - */ - static class LeaseRecord - { - /** - * The lease id. - */ - final VMID vmid; - - /** - * The lease expiration time. - */ - long expireTime; - - /** - * The array of ObjeID's that must be protected from being garbage - * collected. - */ - final ObjID [] objects; - - /** - * Create the new lease record. - * - * @param vmid lease id. - * @param leaseValue lease value - */ - LeaseRecord(VMID vmid, long leaseValue, ObjID [] an_objects) - { - this.vmid = vmid; - reset(leaseValue); - objects = an_objects; - } - - /** - * Prolong the expiration time till current time + passed value - * - * @param leaseValue the value after that (since the current moment) - * the lease should expire in the future. - */ - void reset(long leaseValue) - { - long l = System.currentTimeMillis(); - expireTime = l + leaseValue; - } - - /** - * Check if the lease has been expired. - * - * @return true if the lease has been expired, false if it is still valid. - */ - boolean isExpired() - { - long l = System.currentTimeMillis(); - if (l > expireTime) - return true; - return false; - } - - } // End of LeaseRecord - } // End of DGCImpl diff --git a/libjava/classpath/gnu/java/rmi/dgc/LeaseRenewingTask.java b/libjava/classpath/gnu/java/rmi/dgc/LeaseRenewingTask.java new file mode 100644 index 00000000000..ffb5560afdf --- /dev/null +++ b/libjava/classpath/gnu/java/rmi/dgc/LeaseRenewingTask.java @@ -0,0 +1,234 @@ +/* LeaseRenewingTask.java -- The task to renew the lease. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.rmi.dgc; + +import gnu.java.rmi.server.UnicastRef; + +import java.lang.ref.WeakReference; +import java.rmi.dgc.Lease; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.Timer; +import java.util.TimerTask; +import java.util.WeakHashMap; + +/** + * The task to renew the lease to some object reference. The UnicastRef + * being renewed is stored as a weak reference. So the presence of the + * sheduled task does not prevent it from being garbage collected. If the + * reference has not been garbage collected, the task is resheduled after + * the lease is renewed. + * + * @author Audrius Meskauskas (Audriusa@Bioinformatics.org) + */ +public class LeaseRenewingTask +{ + /** + * The sheduled timer task to call the renew() method. + */ + class LeaseTimerTask extends TimerTask + { + public void run() + { + renew(); + } + } + + /** + * The default requested lease duration time (one minute by default). + */ + public static long REQUEST_LEASE_DURATION = 60000; + + /** + * The reference to the UnicastRef that must renew its lease until not + * garbage collected. The different members of this list may point to the + * different instances of the UnicastRef's, but these references are + * pointing to the same remote object (they .equals() returns + * true when comparing with each other). Using LinkedList to make + * frequent deletions from the middle easy. + */ + LinkedList ref = new LinkedList(); + + /** + * The granted (or supposed) lease. + */ + Lease lease = new Lease(null, REQUEST_LEASE_DURATION); + + /** + * The timer, shared by all lease renewing tasks. The same instance is also + * used for the reference protector discarding in DGCImpl. + */ + static Timer timer = new Timer(true); + + /** + * Maps the UnicastRef to its renewing task. + */ + static WeakHashMap existingTasks = new WeakHashMap(); + + /** + * Creates the lease renewing task that renews the lease of the given + * UnicastRef until it is not collected. This constructor requests the lease + * value from the server and schedules the lease renewal action. + * + * @param renewIt the reference that must be renewed. + */ + public LeaseRenewingTask(UnicastRef renewIt) + { + lease = notifyDGC(renewIt); + if (lease != null) + { + schedule(lease); + ref.add(new WeakReference(renewIt)); + } + } + + /** + * Schedule periodic leases for the given UnicastRef reference. + * + * @param renewIt the reference, for that the leases must be scheduled. + */ + public static void scheduleLeases(UnicastRef renewIt) + { + // No need to schedule leases for null. + if (renewIt == null) + return; + try { + synchronized (existingTasks) + { + // Check maybe the task for refreshing this remote object already + // exists. + LeaseRenewingTask task = (LeaseRenewingTask) existingTasks.get(renewIt); + + if (task != null) + { + // Extend the reference list only. The scheduling must be + // alredy done with the previous lease. + synchronized (task.ref) + { + task.ref.add(new WeakReference(renewIt)); + } + } + else + existingTasks.put(renewIt, new LeaseRenewingTask(renewIt)); + } + } + catch (Exception ex) + { + InternalError ierr = new InternalError("Lease for "+renewIt); + ierr.initCause(ex); + throw ierr; + } + } + + /** + * Shedule the renewing call, taking into consideration that the following + * lease was granted. + * + * @param lease the lease that was granted. + */ + public void schedule(Lease lease) + { + long value = lease.getValue(); + + // Shedule a 10 % earlier because some time is needed for the message + // to reach the server. + long reduced = (value * 90)/100; + if (reduced == 0) + reduced = value; + + timer.schedule(new LeaseTimerTask(), reduced); + } + + /** + * Renew the lease. + */ + public void renew() + { + Object renewIt = null; + // Iterate throw the list of associated references. If all are + // discarded, there is no need to renew. + synchronized (ref) + { + Iterator iter = ref.iterator(); + WeakReference w; + while (iter.hasNext() && renewIt == null) + { + w = (WeakReference) iter.next(); + renewIt = w.get(); + if (renewIt == null) + // Discard the weak reference if its target has been garbage + // collected. + iter.remove(); + } + } + + if (renewIt!=null) + { + Lease lease = notifyDGC( (UnicastRef) renewIt); + + // Schedule the next renewing session. + if (lease!=null) + schedule(lease); + } + { + // All references collected - discard this entry. + } + } + + /** + * Notify DGC that we still hold this reference. + * + * @param renewIt the reference we still have (must not be null). + */ + public Lease notifyDGC(UnicastRef renewIt) + { + try + { + return renewIt.notifyDGC(lease); + } + catch (Exception e) + { + // Failed to notify. + // TODO Take some relevant action in the case if we failed + // to notify the remote object owner. + return null; + } + } + +} |