Author: markt
Date: Wed Aug 17 17:03:35 2011
New Revision: 1158831
URL: http://svn.apache.org/viewvc?rev=1158831&view=rev
Log:
POOL-98. Add additional attributes for moniroting (also available via JMX)
Modified:
commons/proper/pool/trunk/src/changes/changes.xml
commons/proper/pool/trunk/src/java/org/apache/commons/pool2/impl/GenericKeyedObjectPool.java
commons/proper/pool/trunk/src/java/org/apache/commons/pool2/impl/GenericKeyedObjectPoolMBean.java
commons/proper/pool/trunk/src/java/org/apache/commons/pool2/impl/GenericObjectPool.java
commons/proper/pool/trunk/src/java/org/apache/commons/pool2/impl/GenericObjectPoolMBean.java
commons/proper/pool/trunk/src/java/org/apache/commons/pool2/impl/PooledObject.java
Modified: commons/proper/pool/trunk/src/changes/changes.xml
URL:
http://svn.apache.org/viewvc/commons/proper/pool/trunk/src/changes/changes.xml?rev=1158831&r1=1158830&r2=1158831&view=diff
==============================================================================
--- commons/proper/pool/trunk/src/changes/changes.xml (original)
+++ commons/proper/pool/trunk/src/changes/changes.xml Wed Aug 17 17:03:35 2011
@@ -77,6 +77,9 @@
<action dev="markt" type="update" issue="POOL-172">
Expose GOP and GKOP attributes via JMX.
</action>
+ <action dev="markt" type="update" issue="POOL-98">
+ Add additional attributes (also accessible via JMX) for monitoring.
+ </action>
</release>
<release version="1.5.6" date="2011-04-03" description="This is a patch
release, including bugfixes only.">
<action dev="markt" type="fix" issue="POOL-179" due-to="Axel Grossmann">
Modified:
commons/proper/pool/trunk/src/java/org/apache/commons/pool2/impl/GenericKeyedObjectPool.java
URL:
http://svn.apache.org/viewvc/commons/proper/pool/trunk/src/java/org/apache/commons/pool2/impl/GenericKeyedObjectPool.java?rev=1158831&r1=1158830&r2=1158831&view=diff
==============================================================================
---
commons/proper/pool/trunk/src/java/org/apache/commons/pool2/impl/GenericKeyedObjectPool.java
(original)
+++
commons/proper/pool/trunk/src/java/org/apache/commons/pool2/impl/GenericKeyedObjectPool.java
Wed Aug 17 17:03:35 2011
@@ -19,8 +19,10 @@ package org.apache.commons.pool2.impl;
import java.lang.management.ManagementFactory;
import java.util.ArrayList;
+import java.util.Deque;
import java.util.HashMap;
import java.util.Iterator;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@@ -253,6 +255,8 @@ public class GenericKeyedObjectPool<K,T>
startEvictor(getMinEvictableIdleTimeMillis());
+ initStats();
+
// JMX Registration
if (config.isJmxEnabled()) {
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
@@ -734,6 +738,7 @@ public class GenericKeyedObjectPool<K,T>
boolean blockWhenExhausted = this.blockWhenExhausted;
boolean create;
+ long waitTime = 0;
ObjectDeque<T> objectDeque = register(key);
try {
@@ -751,8 +756,10 @@ public class GenericKeyedObjectPool<K,T>
if (borrowMaxWait < 1) {
p = objectDeque.getIdleObjects().takeFirst();
} else {
+ waitTime = System.currentTimeMillis();
p = objectDeque.getIdleObjects().pollFirst(
borrowMaxWait, TimeUnit.MILLISECONDS);
+ waitTime = System.currentTimeMillis() - waitTime;
}
}
if (p == null) {
@@ -806,6 +813,7 @@ public class GenericKeyedObjectPool<K,T>
if (!validate) {
try {
destroy(key, p, true);
+
destroyedByBorrowValidationCount.incrementAndGet();
} catch (Exception e) {
// Ignore - validation failure is more
important
}
@@ -823,7 +831,21 @@ public class GenericKeyedObjectPool<K,T>
} finally {
deregister(key);
}
- return p.getObject();
+
+ borrowedCount.incrementAndGet();
+ synchronized (idleTimes) {
+ idleTimes.add(Long.valueOf(p.getIdleTimeMillis()));
+ idleTimes.poll();
+ }
+ synchronized (waitTimes) {
+ waitTimes.add(Long.valueOf(waitTime));
+ waitTimes.poll();
+ }
+ synchronized (maxBorrowWaitTimeMillisLock) {
+ if (waitTime > maxBorrowWaitTimeMillis) {
+ maxBorrowWaitTimeMillis = waitTime;
+ }
+ } return p.getObject();
}
@@ -857,6 +879,8 @@ public class GenericKeyedObjectPool<K,T>
"Returned object not currently part of this pool");
}
+ long activeTime = p.getActiveTimeMillis();
+
if (getTestOnReturn()) {
if (!_factory.validateObject(key, t)) {
try {
@@ -864,6 +888,7 @@ public class GenericKeyedObjectPool<K,T>
} catch (Exception e) {
// TODO - Ignore?
}
+ updateStatsReturn(activeTime);
return;
}
}
@@ -876,6 +901,7 @@ public class GenericKeyedObjectPool<K,T>
} catch (Exception e) {
// TODO - Ignore?
}
+ updateStatsReturn(activeTime);
return;
}
@@ -901,9 +927,19 @@ public class GenericKeyedObjectPool<K,T>
idleObjects.addLast(p);
}
}
+ updateStatsReturn(activeTime);
}
+ private void updateStatsReturn(long activeTime) {
+ returnedCount.incrementAndGet();
+ synchronized (activeTimes) {
+ activeTimes.add(Long.valueOf(activeTime));
+ activeTimes.poll();
+ }
+ }
+
+
/**
* {@inheritDoc}
* <p>Activation of this method decrements the active count associated
with
@@ -1195,6 +1231,7 @@ public class GenericKeyedObjectPool<K,T>
if (idleEvictTime < underTest.getIdleTimeMillis()) {
destroy(evictionKey, underTest, true);
+ destroyedByEvictorCount.incrementAndGet();
} else {
if (testWhileIdle) {
boolean active = false;
@@ -1204,17 +1241,20 @@ public class GenericKeyedObjectPool<K,T>
active = true;
} catch (Exception e) {
destroy(evictionKey, underTest, true);
+ destroyedByEvictorCount.incrementAndGet();
}
if (active) {
if (!_factory.validateObject(evictionKey,
underTest.getObject())) {
destroy(evictionKey, underTest, true);
+ destroyedByEvictorCount.incrementAndGet();
} else {
try {
_factory.passivateObject(evictionKey,
underTest.getObject());
} catch (Exception e) {
destroy(evictionKey, underTest, true);
+ destroyedByEvictorCount.incrementAndGet();
}
}
}
@@ -1269,6 +1309,7 @@ public class GenericKeyedObjectPool<K,T>
}
PooledObject<T> p = new PooledObject<T>(t);
+ createdCount.incrementAndGet();
objectDeque.getAllObjects().put(t, p);
return p;
}
@@ -1289,6 +1330,7 @@ public class GenericKeyedObjectPool<K,T>
_factory.destroyObject(key, toDestory.getObject());
} finally {
objectDeque.getCreateCount().decrementAndGet();
+ destroyedCount.incrementAndGet();
numTotal.decrementAndGet();
}
return true;
@@ -1556,6 +1598,34 @@ public class GenericKeyedObjectPool<K,T>
//--- JMX specific attributes
----------------------------------------------
+
+ private void initStats() {
+ for (int i = 0; i < AVERAGE_TIMING_STATS_CACHE_SIZE; i++) {
+ activeTimes.add(null);
+ idleTimes.add(null);
+ waitTimes.add(null);
+ }
+ }
+
+ private long getMeanFromStatsCache(Deque<Long> cache) {
+ List<Long> times = new
ArrayList<Long>(AVERAGE_TIMING_STATS_CACHE_SIZE);
+ synchronized (cache) {
+ times.addAll(cache);
+ }
+ double result = 0;
+ int counter = 0;
+ Iterator<Long> iter = times.iterator();
+ while (iter.hasNext()) {
+ Long time = iter.next();
+ if (time != null) {
+ counter++;
+ result = result * ((counter - 1) / counter) +
+ time.longValue()/counter;
+ }
+ }
+ return (long) result;
+ }
+
public Map<String,Integer> getNumActivePerKey() {
HashMap<String,Integer> result = new HashMap<String,Integer>();
@@ -1574,7 +1644,47 @@ public class GenericKeyedObjectPool<K,T>
}
return result;
}
-
+
+ public long getBorrowedCount() {
+ return borrowedCount.get();
+ }
+
+ public long getReturnedCount() {
+ return returnedCount.get();
+ }
+
+ public long getCreatedCount() {
+ return createdCount.get();
+ }
+
+ public long getDestroyedCount() {
+ return destroyedCount.get();
+ }
+
+ public long getDestroyedByEvictorCount() {
+ return destroyedByEvictorCount.get();
+ }
+
+ public long getDestroyedByBorrowValidationCount() {
+ return destroyedByBorrowValidationCount.get();
+ }
+
+ public long getMeanActiveTimeMillis() {
+ return getMeanFromStatsCache(activeTimes);
+ }
+
+ public long getMeanIdleTimeMillis() {
+ return getMeanFromStatsCache(idleTimes);
+ }
+
+ public long getMeanBorrowWaitTimeMillis() {
+ return getMeanFromStatsCache(waitTimes);
+ }
+
+ public long getMaxBorrowWaitTimeMillis() {
+ return maxBorrowWaitTimeMillis;
+ }
+
//--- inner classes ----------------------------------------------
/**
@@ -1826,6 +1936,20 @@ public class GenericKeyedObjectPool<K,T>
*/
private K evictionKey = null;
+ // JMX specific attributes
+ private static final int AVERAGE_TIMING_STATS_CACHE_SIZE = 100;
+ private AtomicLong borrowedCount = new AtomicLong(0);
+ private AtomicLong returnedCount = new AtomicLong(0);
+ private AtomicLong createdCount = new AtomicLong(0);
+ private AtomicLong destroyedCount = new AtomicLong(0);
+ private AtomicLong destroyedByEvictorCount = new AtomicLong(0);
+ private AtomicLong destroyedByBorrowValidationCount = new AtomicLong(0);
+ private final Deque<Long> activeTimes = new LinkedList<Long>();
+ private final Deque<Long> idleTimes = new LinkedList<Long>();
+ private final Deque<Long> waitTimes = new LinkedList<Long>();
+ private Object maxBorrowWaitTimeMillisLock = new Object();
+ private volatile long maxBorrowWaitTimeMillis = 0;
+
private static final String ONAME_BASE =
"org.apache.commoms.pool2:type=GenericKeyedObjectPool,name=";
}
Modified:
commons/proper/pool/trunk/src/java/org/apache/commons/pool2/impl/GenericKeyedObjectPoolMBean.java
URL:
http://svn.apache.org/viewvc/commons/proper/pool/trunk/src/java/org/apache/commons/pool2/impl/GenericKeyedObjectPoolMBean.java?rev=1158831&r1=1158830&r2=1158831&view=diff
==============================================================================
---
commons/proper/pool/trunk/src/java/org/apache/commons/pool2/impl/GenericKeyedObjectPoolMBean.java
(original)
+++
commons/proper/pool/trunk/src/java/org/apache/commons/pool2/impl/GenericKeyedObjectPoolMBean.java
Wed Aug 17 17:03:35 2011
@@ -38,4 +38,14 @@ public interface GenericKeyedObjectPoolM
boolean isClosed();
// JMX specific attributes
Map<String,Integer> getNumActivePerKey();
+ long getBorrowedCount();
+ long getReturnedCount();
+ long getCreatedCount();
+ long getDestroyedCount();
+ long getDestroyedByEvictorCount();
+ long getDestroyedByBorrowValidationCount();
+ long getMeanActiveTimeMillis();
+ long getMeanIdleTimeMillis();
+ long getMeanBorrowWaitTimeMillis();
+ long getMaxBorrowWaitTimeMillis();
}
Modified:
commons/proper/pool/trunk/src/java/org/apache/commons/pool2/impl/GenericObjectPool.java
URL:
http://svn.apache.org/viewvc/commons/proper/pool/trunk/src/java/org/apache/commons/pool2/impl/GenericObjectPool.java?rev=1158831&r1=1158830&r2=1158831&view=diff
==============================================================================
---
commons/proper/pool/trunk/src/java/org/apache/commons/pool2/impl/GenericObjectPool.java
(original)
+++
commons/proper/pool/trunk/src/java/org/apache/commons/pool2/impl/GenericObjectPool.java
Wed Aug 17 17:03:35 2011
@@ -18,7 +18,11 @@
package org.apache.commons.pool2.impl;
import java.lang.management.ManagementFactory;
+import java.util.ArrayList;
+import java.util.Deque;
import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.TimerTask;
@@ -205,6 +209,8 @@ public class GenericObjectPool<T> extend
startEvictor(timeBetweenEvictionRunsMillis);
+ initStats();
+
// JMX Registration
if (config.isJmxEnabled()) {
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
@@ -722,6 +728,7 @@ public class GenericObjectPool<T> extend
boolean blockWhenExhausted = this.blockWhenExhausted;
boolean create;
+ long waitTime = 0;
while (p == null) {
create = false;
@@ -735,8 +742,10 @@ public class GenericObjectPool<T> extend
if (borrowMaxWait < 1) {
p = idleObjects.takeFirst();
} else {
+ waitTime = System.currentTimeMillis();
p = idleObjects.pollFirst(borrowMaxWait,
TimeUnit.MILLISECONDS);
+ waitTime = System.currentTimeMillis() - waitTime;
}
}
if (p == null) {
@@ -788,6 +797,7 @@ public class GenericObjectPool<T> extend
if (!validate) {
try {
destroy(p);
+ destroyedByBorrowValidationCount.incrementAndGet();
} catch (Exception e) {
// Ignore - validation failure is more important
}
@@ -803,6 +813,20 @@ public class GenericObjectPool<T> extend
}
}
+ borrowedCount.incrementAndGet();
+ synchronized (idleTimes) {
+ idleTimes.add(Long.valueOf(p.getIdleTimeMillis()));
+ idleTimes.poll();
+ }
+ synchronized (waitTimes) {
+ waitTimes.add(Long.valueOf(waitTime));
+ waitTimes.poll();
+ }
+ synchronized (maxBorrowWaitTimeMillisLock) {
+ if (waitTime > maxBorrowWaitTimeMillis) {
+ maxBorrowWaitTimeMillis = waitTime;
+ }
+ }
return p.getObject();
}
@@ -834,6 +858,8 @@ public class GenericObjectPool<T> extend
"Returned object not currently part of this pool");
}
+ long activeTime = p.getActiveTimeMillis();
+
if (getTestOnReturn()) {
if (!factory.validateObject(obj)) {
try {
@@ -841,6 +867,7 @@ public class GenericObjectPool<T> extend
} catch (Exception e) {
// TODO - Ignore?
}
+ updateStatsReturn(activeTime);
return;
}
}
@@ -853,6 +880,7 @@ public class GenericObjectPool<T> extend
} catch (Exception e) {
// TODO - Ignore?
}
+ updateStatsReturn(activeTime);
return;
}
@@ -875,6 +903,15 @@ public class GenericObjectPool<T> extend
idleObjects.addLast(p);
}
}
+ updateStatsReturn(activeTime);
+ }
+
+ private void updateStatsReturn(long activeTime) {
+ returnedCount.incrementAndGet();
+ synchronized (activeTimes) {
+ activeTimes.add(Long.valueOf(activeTime));
+ activeTimes.poll();
+ }
}
/**
@@ -1040,6 +1077,7 @@ public class GenericObjectPool<T> extend
(idleSoftEvictTime < underTest.getIdleTimeMillis() &&
getMinIdle() < idleObjects.size())) {
destroy(underTest);
+ destroyedByEvictorCount.incrementAndGet();
} else {
if (testWhileIdle) {
boolean active = false;
@@ -1048,15 +1086,18 @@ public class GenericObjectPool<T> extend
active = true;
} catch (Exception e) {
destroy(underTest);
+ destroyedByEvictorCount.incrementAndGet();
}
if (active) {
if (!factory.validateObject(underTest.getObject())) {
destroy(underTest);
+ destroyedByEvictorCount.incrementAndGet();
} else {
try {
factory.passivateObject(underTest.getObject());
} catch (Exception e) {
destroy(underTest);
+ destroyedByEvictorCount.incrementAndGet();
}
}
}
@@ -1089,6 +1130,7 @@ public class GenericObjectPool<T> extend
}
PooledObject<T> p = new PooledObject<T>(t);
+ createdCount.incrementAndGet();
allObjects.put(t, p);
return p;
}
@@ -1099,6 +1141,7 @@ public class GenericObjectPool<T> extend
try {
factory.destroyObject(toDestory.getObject());
} finally {
+ destroyedCount.incrementAndGet();
createCount.decrementAndGet();
}
}
@@ -1212,6 +1255,75 @@ public class GenericObjectPool<T> extend
}
}
+ //--- JMX specific attributes
----------------------------------------------
+
+ private void initStats() {
+ for (int i = 0; i < AVERAGE_TIMING_STATS_CACHE_SIZE; i++) {
+ activeTimes.add(null);
+ idleTimes.add(null);
+ waitTimes.add(null);
+ }
+ }
+
+ private long getMeanFromStatsCache(Deque<Long> cache) {
+ List<Long> times = new
ArrayList<Long>(AVERAGE_TIMING_STATS_CACHE_SIZE);
+ synchronized (cache) {
+ times.addAll(cache);
+ }
+ double result = 0;
+ int counter = 0;
+ Iterator<Long> iter = times.iterator();
+ while (iter.hasNext()) {
+ Long time = iter.next();
+ if (time != null) {
+ counter++;
+ result = result * ((counter - 1) / counter) +
+ time.longValue()/counter;
+ }
+ }
+ return (long) result;
+ }
+
+ public long getBorrowedCount() {
+ return borrowedCount.get();
+ }
+
+ public long getReturnedCount() {
+ return returnedCount.get();
+ }
+
+ public long getCreatedCount() {
+ return createdCount.get();
+ }
+
+ public long getDestroyedCount() {
+ return destroyedCount.get();
+ }
+
+ public long getDestroyedByEvictorCount() {
+ return destroyedByEvictorCount.get();
+ }
+
+ public long getDestroyedByBorrowValidationCount() {
+ return destroyedByBorrowValidationCount.get();
+ }
+
+ public long getMeanActiveTimeMillis() {
+ return getMeanFromStatsCache(activeTimes);
+ }
+
+ public long getMeanIdleTimeMillis() {
+ return getMeanFromStatsCache(idleTimes);
+ }
+
+ public long getMeanBorrowWaitTimeMillis() {
+ return getMeanFromStatsCache(waitTimes);
+ }
+
+ public long getMaxBorrowWaitTimeMillis() {
+ return maxBorrowWaitTimeMillis;
+ }
+
// --- inner classes ----------------------------------------------
/**
@@ -1424,6 +1536,20 @@ public class GenericObjectPool<T> extend
/** An iterator for {@link #idleObjects} that is used by the evictor. */
private Iterator<PooledObject<T>> evictionIterator = null;
+ // JMX specific attributes
+ private static final int AVERAGE_TIMING_STATS_CACHE_SIZE = 100;
+ private AtomicLong borrowedCount = new AtomicLong(0);
+ private AtomicLong returnedCount = new AtomicLong(0);
+ private AtomicLong createdCount = new AtomicLong(0);
+ private AtomicLong destroyedCount = new AtomicLong(0);
+ private AtomicLong destroyedByEvictorCount = new AtomicLong(0);
+ private AtomicLong destroyedByBorrowValidationCount = new AtomicLong(0);
+ private final Deque<Long> activeTimes = new LinkedList<Long>();
+ private final Deque<Long> idleTimes = new LinkedList<Long>();
+ private final Deque<Long> waitTimes = new LinkedList<Long>();
+ private Object maxBorrowWaitTimeMillisLock = new Object();
+ private volatile long maxBorrowWaitTimeMillis = 0;
+
private static final String ONAME_BASE =
"org.apache.commoms.pool2:type=GenericObjectPool,name=";
}
Modified:
commons/proper/pool/trunk/src/java/org/apache/commons/pool2/impl/GenericObjectPoolMBean.java
URL:
http://svn.apache.org/viewvc/commons/proper/pool/trunk/src/java/org/apache/commons/pool2/impl/GenericObjectPoolMBean.java?rev=1158831&r1=1158830&r2=1158831&view=diff
==============================================================================
---
commons/proper/pool/trunk/src/java/org/apache/commons/pool2/impl/GenericObjectPoolMBean.java
(original)
+++
commons/proper/pool/trunk/src/java/org/apache/commons/pool2/impl/GenericObjectPoolMBean.java
Wed Aug 17 17:03:35 2011
@@ -33,4 +33,15 @@ public interface GenericObjectPoolMBean
boolean getTestWhileIdle();
long getTimeBetweenEvictionRunsMillis();
boolean isClosed();
+ // JMX specific attributes
+ long getBorrowedCount();
+ long getReturnedCount();
+ long getCreatedCount();
+ long getDestroyedCount();
+ long getDestroyedByEvictorCount();
+ long getDestroyedByBorrowValidationCount();
+ long getMeanActiveTimeMillis();
+ long getMeanIdleTimeMillis();
+ long getMeanBorrowWaitTimeMillis();
+ long getMaxBorrowWaitTimeMillis();
}
Modified:
commons/proper/pool/trunk/src/java/org/apache/commons/pool2/impl/PooledObject.java
URL:
http://svn.apache.org/viewvc/commons/proper/pool/trunk/src/java/org/apache/commons/pool2/impl/PooledObject.java?rev=1158831&r1=1158830&r2=1158831&view=diff
==============================================================================
---
commons/proper/pool/trunk/src/java/org/apache/commons/pool2/impl/PooledObject.java
(original)
+++
commons/proper/pool/trunk/src/java/org/apache/commons/pool2/impl/PooledObject.java
Wed Aug 17 17:03:35 2011
@@ -25,7 +25,8 @@ public class PooledObject<T> implements
private T object = null;
private volatile PooledObjectState state = PooledObjectState.IDLE;
- private long lastActiveTime = System.currentTimeMillis();
+ private long lastBorrowTime = System.currentTimeMillis();
+ private long lastReturnTime = System.currentTimeMillis();
public PooledObject(T object) {
this.object = object;
@@ -40,19 +41,38 @@ public class PooledObject<T> implements
}
/**
- * Obtain the time in milliseconds since this object was last active.
+ * Obtain the time in milliseconds that this object last spend in the the
+ * active state (it may still be active in which case subsequent calls will
+ * return an increased value).
+ */
+ public long getActiveTimeMillis() {
+ if (lastReturnTime > lastBorrowTime) {
+ return lastReturnTime - lastBorrowTime;
+ } else {
+ return System.currentTimeMillis() - lastBorrowTime;
+ }
+ }
+
+ /**
+ * Obtain the time in milliseconds that this object last spend in the the
+ * idle state (it may still be idle in which case subsequent calls will
+ * return an increased value).
*/
public long getIdleTimeMillis() {
- return System.currentTimeMillis() - lastActiveTime;
+ return System.currentTimeMillis() - lastReturnTime;
}
- public long getLastActiveTime() {
- return lastActiveTime;
+ public long getLastBorrowTime() {
+ return lastBorrowTime;
+ }
+
+ public long getLastReturnTime() {
+ return lastReturnTime;
}
public int compareTo(PooledObject<T> other) {
final long lastActiveDiff =
- this.getLastActiveTime() - other.getLastActiveTime();
+ this.getLastReturnTime() - other.getLastReturnTime();
if (lastActiveDiff == 0) {
// make sure the natural ordering is consistent with equals
// see java.lang.Comparable Javadocs
@@ -104,6 +124,7 @@ public class PooledObject<T> implements
public synchronized boolean allocate() {
if (state == PooledObjectState.IDLE) {
state = PooledObjectState.ALLOCATED;
+ lastBorrowTime = System.currentTimeMillis();
return true;
} else if (state == PooledObjectState.MAINTAIN_EVICTION) {
// TODO Allocate anyway and ignore eviction test
@@ -118,7 +139,7 @@ public class PooledObject<T> implements
public synchronized boolean deallocate() {
if (state == PooledObjectState.ALLOCATED) {
state = PooledObjectState.IDLE;
- lastActiveTime = System.currentTimeMillis();
+ lastReturnTime = System.currentTimeMillis();
return true;
}