001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: *
015: * See the License for the specific language governing permissions and
016: * limitations under the License.
017: */
018:
019: /**
020: * @author Mikhail A. Markov
021: * @version $Revision: 1.1.2.2 $
022: */package org.apache.harmony.rmi.server;
023:
024: import java.rmi.RemoteException;
025: import java.rmi.dgc.DGC;
026: import java.rmi.dgc.Lease;
027: import java.rmi.dgc.VMID;
028: import java.rmi.server.ObjID;
029: import java.security.AccessController;
030: import java.util.Collections;
031: import java.util.Enumeration;
032: import java.util.HashSet;
033: import java.util.Hashtable;
034: import java.util.Iterator;
035: import java.util.Set;
036:
037: import org.apache.harmony.rmi.common.CreateThreadAction;
038: import org.apache.harmony.rmi.common.GetLongPropAction;
039: import org.apache.harmony.rmi.common.RMILog;
040: import org.apache.harmony.rmi.common.RMIProperties;
041: import org.apache.harmony.rmi.internal.nls.Messages;
042:
043: /**
044: * Distributed Garbage Collector implementation (Server side).
045: * It is made package protected for security reasons.
046: *
047: * @author Mikhail A. Markov
048: * @version $Revision: 1.1.2.2 $
049: */
050: class DGCImpl implements DGC {
051:
052: /* Log where to write dgc activity. */
053: static final RMILog dgcLog = RMILog.getDGCLog();
054:
055: /*
056: * Maximum lease duration granted by this DGC.
057: * Default value is 10 minutes.
058: */
059: static final long maxDuration = ((Long) AccessController
060: .doPrivileged(new GetLongPropAction(
061: RMIProperties.DGCLEASEVALUE_PROP, 10 * 60 * 1000)))
062: .longValue();
063:
064: /*
065: * How often we will check DGC leases.
066: * Default value is half of maxDuration time.
067: */
068: private static final long checkInterval = ((Long) AccessController
069: .doPrivileged(new GetLongPropAction(
070: RMIProperties.DGCCHECKINTERVAL_PROP,
071: maxDuration / 2))).longValue();
072:
073: /*
074: * Table where VMIDs are keys and HashSets of ObjIDs are the values.
075: */
076: private Hashtable vmidTable = new Hashtable();
077:
078: // Thread checking leases expirations.
079: private static Thread expTracker;
080:
081: /**
082: * @see DGC.dirty(ObjID[], long, Lease)
083: */
084: public Lease dirty(ObjID[] ids, long seqNum, Lease lease)
085: throws RemoteException {
086: VMID vmid = lease.getVMID();
087:
088: if (vmid == null) {
089: vmid = new VMID();
090:
091: if (dgcLog.isLoggable(RMILog.VERBOSE)) {
092: // rmi.log.10E=Created new VMID: {0}
093: dgcLog.log(RMILog.VERBOSE, Messages.getString(
094: "rmi.log.10E", vmid)); //$NON-NLS-1$
095: }
096: }
097: long duration = lease.getValue();
098: if (duration > maxDuration || duration < 0) {
099: duration = maxDuration;
100: }
101: Lease l = new Lease(vmid, duration);
102:
103: synchronized (vmidTable) {
104: Set s = (Set) vmidTable.get(vmid);
105:
106: if (s == null) {
107: if (ids == null || ids.length == 0) {
108: // Nothing to do: no VM with such VMID registered
109: return l;
110: }
111: s = Collections.synchronizedSet(new HashSet());
112: vmidTable.put(vmid, s);
113: }
114:
115: if (expTracker == null) {
116: (expTracker = (Thread) AccessController
117: .doPrivileged(new CreateThreadAction(
118: new ExpirationTracker(),
119: "ExpirationTracker", true))).start(); //$NON-NLS-1$
120: }
121:
122: for (int i = 0; i < ids.length; ++i) {
123: s.add(ids[i]);
124:
125: if (dgcLog.isLoggable(RMILog.VERBOSE)) {
126: // rmi.log.10F=Added {0}, {1}, duration ={2}
127: dgcLog.log(RMILog.VERBOSE, Messages.getString(
128: "rmi.log.10F", //$NON-NLS-1$
129: new Object[] { ids[i], vmid, duration }));
130: }
131: }
132:
133: for (Iterator allIds = s.iterator(); allIds.hasNext();) {
134: RMIObjectInfo info = ExportManager
135: .getInfo((ObjID) allIds.next());
136:
137: if (info == null) {
138: /*
139: * Object with this id has not been exported or has been
140: * garbage-collected.
141: */
142: allIds.remove();
143: continue;
144: }
145: info.dgcDirty(vmid, seqNum, duration);
146: }
147: }
148:
149: if (dgcLog.isLoggable(RMILog.VERBOSE)) {
150: // rmi.log.110=Updated {0}
151: dgcLog.log(RMILog.VERBOSE, Messages.getString(
152: "rmi.log.110", vmid)); //$NON-NLS-1$
153: }
154: return l;
155: }
156:
157: /**
158: * @see DGC.clean(ObjID[], long, VMID, boolean)
159: */
160: public void clean(ObjID[] ids, long seqNum, VMID vmid,
161: boolean strong) throws RemoteException {
162: synchronized (vmidTable) {
163: Set s = (Set) vmidTable.get(vmid);
164:
165: if (s == null) {
166: return;
167: }
168:
169: if (ids != null && ids.length > 0) {
170: for (int i = 0; i < ids.length; ++i) {
171: RMIObjectInfo info = ExportManager.getInfo(ids[i]);
172:
173: if (info == null
174: || info.dgcClean(vmid, seqNum, strong)) {
175: s.remove(ids[i]);
176:
177: if (dgcLog.isLoggable(RMILog.VERBOSE)) {
178: // rmi.log.111=Removed {0},{1}
179: dgcLog.log(RMILog.VERBOSE, Messages
180: .getString("rmi.log.111", //$NON-NLS-1$
181: ids[i], vmid));
182: }
183: }
184: }
185: } else {
186: for (Iterator allIds = s.iterator(); allIds.hasNext();) {
187: RMIObjectInfo info = ExportManager
188: .getInfo((ObjID) allIds.next());
189:
190: if (info == null
191: || info.dgcClean(vmid, seqNum, strong)) {
192: allIds.remove();
193: }
194: }
195: }
196:
197: if (s.isEmpty()) {
198: vmidTable.remove(vmid);
199:
200: if (dgcLog.isLoggable(RMILog.VERBOSE)) {
201: // rmi.log.112=Removed {0}
202: dgcLog.log(RMILog.VERBOSE, Messages.getString(
203: "rmi.log.112", vmid)); //$NON-NLS-1$
204: }
205: }
206: }
207: }
208:
209: /*
210: * Auxiliary class checking expiration times and removing expired entries
211: * from the list of active objects.
212: */
213: private class ExpirationTracker implements Runnable {
214: /**
215: * Checks expiration times until no objects left in the table.
216: * Sleeps for a checkInterval period of time between checks.
217: */
218: public void run() {
219: do {
220: try {
221: Thread.sleep(checkInterval);
222: } catch (InterruptedException ie) {
223: }
224: } while (checkExpiration());
225: expTracker = null;
226: }
227:
228: /*
229: * Checks expiration times and removes expired entries
230: * from the list of active objects.
231: *
232: * @return false if there are no objects in the table left and false
233: * otherwise
234: */
235: boolean checkExpiration() {
236: if (vmidTable.size() == 0) {
237: return false;
238: }
239: long curTime = System.currentTimeMillis();
240:
241: synchronized (vmidTable) {
242: for (Enumeration en = vmidTable.keys(); en
243: .hasMoreElements();) {
244: VMID vmid = (VMID) en.nextElement();
245: Set s = (Set) vmidTable.get(vmid);
246:
247: for (Iterator iter = s.iterator(); iter.hasNext();) {
248: RMIObjectInfo info = ExportManager
249: .getInfo((ObjID) iter.next());
250:
251: if (info == null || info.dgcClean(vmid)) {
252: iter.remove();
253:
254: if (info != null
255: && dgcLog
256: .isLoggable(RMILog.VERBOSE)) {
257: dgcLog.log(RMILog.VERBOSE, Messages
258: .getString("rmi.log.113", //$NON-NLS-1$
259: info.id, vmid));
260: }
261: }
262: }
263: }
264: }
265: return true;
266: }
267: }
268: }
|