Author: trustin
Date: Sun Nov 11 16:34:23 2007
New Revision: 594000
URL: http://svn.apache.org/viewvc?rev=594000&view=rev
Log:
Resolved issue: DIRMINA-473 (ReadThrottleFilter throws IllegalStateException)
* Fixed a concurrency issue in size estimators.
* More sanity check code in IoEventQueueThrottle
Modified:
mina/trunk/core/src/main/java/org/apache/mina/filter/executor/DefaultIoEventSizeEstimator.java
mina/trunk/core/src/main/java/org/apache/mina/filter/executor/IoEventQueueThrottle.java
mina/trunk/core/src/main/java/org/apache/mina/filter/traffic/DefaultMessageSizeEstimator.java
Modified:
mina/trunk/core/src/main/java/org/apache/mina/filter/executor/DefaultIoEventSizeEstimator.java
URL:
http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/filter/executor/DefaultIoEventSizeEstimator.java?rev=594000&r1=593999&r2=594000&view=diff
==============================================================================
---
mina/trunk/core/src/main/java/org/apache/mina/filter/executor/DefaultIoEventSizeEstimator.java
(original)
+++
mina/trunk/core/src/main/java/org/apache/mina/filter/executor/DefaultIoEventSizeEstimator.java
Sun Nov 11 16:34:23 2007
@@ -21,8 +21,10 @@
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
-import java.util.Map;
+import java.util.HashSet;
+import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import org.apache.mina.common.IoBuffer;
import org.apache.mina.common.IoEvent;
@@ -43,19 +45,9 @@
*/
public class DefaultIoEventSizeEstimator implements IoEventSizeEstimator {
- private final Map<Class<?>, Integer> class2size = new
ConcurrentHashMap<Class<?>, Integer>();
- private final int averageSizePerField;
+ private final ConcurrentMap<Class<?>, Integer> class2size = new
ConcurrentHashMap<Class<?>, Integer>();
public DefaultIoEventSizeEstimator() {
- this(64);
- }
-
- public DefaultIoEventSizeEstimator(int averageSizePerField) {
- if (averageSizePerField <= 0) {
- throw new IllegalArgumentException("averageSizePerField: " +
averageSizePerField);
- }
- this.averageSizePerField = averageSizePerField;
-
class2size.put(boolean.class, 4); // Probably an integer.
class2size.put(byte.class, 1);
class2size.put(char.class, 2);
@@ -69,87 +61,62 @@
return estimateSize((Object) event) +
estimateSize(event.getParameter());
}
- private int estimateSize(Object message) {
+ public int estimateSize(Object message) {
if (message == null) {
return 8;
}
- if (message instanceof IoBuffer) {
- return align(46 + ((IoBuffer) message).remaining());
- }
+ int answer = 8 + estimateSize(message.getClass(), null);
- if (message instanceof CharSequence) {
- return align(38 + (((CharSequence) message).length() << 1));
- }
-
- if (message instanceof Iterable) {
- int answer = estimateSize(message.getClass());
+ if (message instanceof IoBuffer) {
+ answer += ((IoBuffer) message).remaining();
+ } else if (message instanceof CharSequence) {
+ answer += ((CharSequence) message).length() << 1;
+ } else if (message instanceof Iterable) {
for (Object m: (Iterable<?>) message) {
answer += estimateSize(m);
}
- return answer;
}
- return estimateSize(message.getClass());
+ return align(answer);
}
- private int estimateSize(Class<?> clazz) {
+ private int estimateSize(Class<?> clazz, Set<Class<?>> visitedClasses) {
Integer objectSize = class2size.get(clazz);
if (objectSize != null) {
return objectSize;
}
- int answer = 8; // Basic overhead.
- synchronized (class2size) {
-
- // Get the rough estimation.
- for (Class<?> c = clazz; c != null; c = c.getSuperclass()) {
- Field[] fields = c.getDeclaredFields();
- for (Field f: fields) {
- if ((f.getModifiers() & Modifier.STATIC) != 0) {
- // Ignore static fields.
- continue;
- }
-
- Integer fieldSize = class2size.get(f.getType());
- if (fieldSize == null) {
- answer += averageSizePerField;
- } else {
- answer += fieldSize;
- }
- }
+ if (visitedClasses != null) {
+ if (visitedClasses.contains(clazz)) {
+ return 0;
}
-
- // Put the intermediate answer to prevent infinite recursion.
- class2size.put(clazz, answer);
-
- // Now include field classes, too.
- for (Class<?> c = clazz; c != null; c = c.getSuperclass()) {
- Field[] fields = c.getDeclaredFields();
- for (Field f: fields) {
- if ((f.getModifiers() & Modifier.STATIC) != 0) {
- // Ignore static fields.
- continue;
- }
-
- if (!class2size.containsKey(f.getType())) {
- // Compensate previous rough estimation
- answer += estimateSize(f.getType()) -
averageSizePerField;
- }
+ } else {
+ visitedClasses = new HashSet<Class<?>>();
+ }
+
+ visitedClasses.add(clazz);
+
+ int answer = 8; // Basic overhead.
+ for (Class<?> c = clazz; c != null; c = c.getSuperclass()) {
+ Field[] fields = c.getDeclaredFields();
+ for (Field f: fields) {
+ if ((f.getModifiers() & Modifier.STATIC) != 0) {
+ // Ignore static fields.
+ continue;
}
+
+ answer += estimateSize(f.getType(), visitedClasses);
}
-
- if (answer <= 0) {
- answer = averageSizePerField;
- }
-
- // Some alignment.
- answer = align(answer);
-
- // Put the final answer.
- class2size.put(clazz, answer);
}
+
+ visitedClasses.remove(clazz);
+
+ // Some alignment.
+ answer = align(answer);
+ // Put the final answer.
+ class2size.putIfAbsent(clazz, answer);
return answer;
}
Modified:
mina/trunk/core/src/main/java/org/apache/mina/filter/executor/IoEventQueueThrottle.java
URL:
http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/filter/executor/IoEventQueueThrottle.java?rev=594000&r1=593999&r2=594000&view=diff
==============================================================================
---
mina/trunk/core/src/main/java/org/apache/mina/filter/executor/IoEventQueueThrottle.java
(original)
+++
mina/trunk/core/src/main/java/org/apache/mina/filter/executor/IoEventQueueThrottle.java
Sun Nov 11 16:34:23 2007
@@ -93,10 +93,7 @@
public void polled(ThreadPoolExecutor executor, IoEvent event) {
int eventSize = estimateSize(event);
int currentCounter = counter.addAndGet(-eventSize);
- if (currentCounter < 0) {
- throw new IllegalStateException("counter: " + currentCounter);
- }
-
+
logState();
if (currentCounter < threshold) {
Modified:
mina/trunk/core/src/main/java/org/apache/mina/filter/traffic/DefaultMessageSizeEstimator.java
URL:
http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/filter/traffic/DefaultMessageSizeEstimator.java?rev=594000&r1=593999&r2=594000&view=diff
==============================================================================
---
mina/trunk/core/src/main/java/org/apache/mina/filter/traffic/DefaultMessageSizeEstimator.java
(original)
+++
mina/trunk/core/src/main/java/org/apache/mina/filter/traffic/DefaultMessageSizeEstimator.java
Sun Nov 11 16:34:23 2007
@@ -21,8 +21,10 @@
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
-import java.util.Map;
+import java.util.HashSet;
+import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import org.apache.mina.common.IoBuffer;
@@ -42,19 +44,9 @@
*/
public class DefaultMessageSizeEstimator implements MessageSizeEstimator {
- private final Map<Class<?>, Integer> class2size = new
ConcurrentHashMap<Class<?>, Integer>();
- private final int averageSizePerField;
+ private final ConcurrentMap<Class<?>, Integer> class2size = new
ConcurrentHashMap<Class<?>, Integer>();
public DefaultMessageSizeEstimator() {
- this(64);
- }
-
- public DefaultMessageSizeEstimator(int averageSizePerField) {
- if (averageSizePerField <= 0) {
- throw new IllegalArgumentException("averageSizePerField: " +
averageSizePerField);
- }
- this.averageSizePerField = averageSizePerField;
-
class2size.put(boolean.class, 4); // Probably an integer.
class2size.put(byte.class, 1);
class2size.put(char.class, 2);
@@ -65,82 +57,61 @@
}
public int estimateSize(Object message) {
- if (message instanceof IoBuffer) {
- return align(46 + ((IoBuffer) message).remaining());
- }
-
- if (message instanceof CharSequence) {
- return align(38 + (((CharSequence) message).length() << 1));
+ if (message == null) {
+ return 8;
}
+
+ int answer = 8 + estimateSize(message.getClass(), null);
- if (message instanceof Iterable) {
- int answer = estimateSize(message.getClass());
+ if (message instanceof IoBuffer) {
+ answer += ((IoBuffer) message).remaining();
+ } else if (message instanceof CharSequence) {
+ answer += ((CharSequence) message).length() << 1;
+ } else if (message instanceof Iterable) {
for (Object m: (Iterable<?>) message) {
answer += estimateSize(m);
}
- return answer;
}
- return estimateSize(message.getClass());
+ return align(answer);
}
- private int estimateSize(Class<?> clazz) {
+ private int estimateSize(Class<?> clazz, Set<Class<?>> visitedClasses) {
Integer objectSize = class2size.get(clazz);
if (objectSize != null) {
return objectSize;
}
- int answer = 8; // Basic overhead.
- synchronized (class2size) {
-
- // Get the rough estimation.
- for (Class<?> c = clazz; c != null; c = c.getSuperclass()) {
- Field[] fields = c.getDeclaredFields();
- for (Field f: fields) {
- if ((f.getModifiers() & Modifier.STATIC) != 0) {
- // Ignore static fields.
- continue;
- }
-
- Integer fieldSize = class2size.get(f.getType());
- if (fieldSize == null) {
- answer += averageSizePerField;
- } else {
- answer += fieldSize;
- }
- }
+ if (visitedClasses != null) {
+ if (visitedClasses.contains(clazz)) {
+ return 0;
}
-
- // Put the intermediate answer to prevent infinite recursion.
- class2size.put(clazz, answer);
-
- // Now include field classes, too.
- for (Class<?> c = clazz; c != null; c = c.getSuperclass()) {
- Field[] fields = c.getDeclaredFields();
- for (Field f: fields) {
- if ((f.getModifiers() & Modifier.STATIC) != 0) {
- // Ignore static fields.
- continue;
- }
-
- if (!class2size.containsKey(f.getType())) {
- // Compensate previous rough estimation
- answer += estimateSize(f.getType()) -
averageSizePerField;
- }
+ } else {
+ visitedClasses = new HashSet<Class<?>>();
+ }
+
+ visitedClasses.add(clazz);
+
+ int answer = 8; // Basic overhead.
+ for (Class<?> c = clazz; c != null; c = c.getSuperclass()) {
+ Field[] fields = c.getDeclaredFields();
+ for (Field f: fields) {
+ if ((f.getModifiers() & Modifier.STATIC) != 0) {
+ // Ignore static fields.
+ continue;
}
+
+ answer += estimateSize(f.getType(), visitedClasses);
}
-
- if (answer <= 0) {
- answer = averageSizePerField;
- }
-
- // Some alignment.
- answer = align(answer);
-
- // Put the final answer.
- class2size.put(clazz, answer);
}
+
+ visitedClasses.remove(clazz);
+
+ // Some alignment.
+ answer = align(answer);
+ // Put the final answer.
+ class2size.putIfAbsent(clazz, answer);
return answer;
}