Gareth Carter created OFBIZ-6621:
------------------------------------
Summary: MapContext.entrySet() slows down when ByteBuffer objects
are in the context
Key: OFBIZ-6621
URL: https://issues.apache.org/jira/browse/OFBIZ-6621
Project: OFBiz
Issue Type: Improvement
Components: framework
Affects Versions: Trunk
Reporter: Gareth Carter
Priority: Critical
When MapContext is used anywhere (eg FlexibleStringExpander) and the context
contains ByteBuffer objects (either key or value), java will slow down when
calling MapContext.entrySet().
Here is the code in ofbiz, highlighted is the line of code that I believe is
the culprit
{code:title=MapContext.java}
public Set<Map.Entry<K, V>> entrySet() {
// walk the stackList and the entries for each Map and if nothing is in for
the current key, put it in
Set<K> resultKeySet = new HashSet<K>();
culprit --> Set<Map.Entry<K, V>> resultEntrySet = new ListSet<Map.Entry<K,
V>>();
for (Map<K, V> curMap: this.stackList) {
for (Map.Entry<K, V> curEntry: curMap.entrySet()) {
if (!resultKeySet.contains(curEntry.getKey())) {
resultKeySet.add(curEntry.getKey());
resultEntrySet.add(curEntry);
}
}
}
return Collections.unmodifiableSet(resultEntrySet);
}
{code}
Looking at the java api for Map.Entry, the hashCode method for Map.Entry is the
result of the hashCode from both key and value. ByteBuffer hash code is
dependent upon its content. If a 2mb file is uploaded, the hashCode method
of ByteBuffer will scan 2mb to generate the hashCode
ByteBuffer
http://docs.oracle.com/javase/7/docs/api/java/nio/ByteBuffer.html#hashCode()
{quote}Because buffer hash codes are content-dependent, it is inadvisable to
use buffers as keys in hash maps or similar data structures unless it is known
that their contents will not change.{quote}
Map.Entry
http://docs.oracle.com/javase/7/docs/api/java/util/Map.Entry.html#hashCode()
{quote}(e.getKey()==null ? 0 : e.getKey().hashCode()) ^ (e.getValue()==null ?
0 : e.getValue().hashCode()){quote}
HashSet
http://docs.oracle.com/javase/7/docs/api/java/util/HashSet.html
{quote}This class implements the Set interface, backed by a hash table
(actually a HashMap instance{quote}
Example where ByteBuffer objects are created
{code}org.ofbiz.webapp.event.ServiceEventHandler{code}
Example stack trace
{noformat}
"ajp-bio-8009-exec-1894" daemon prio=10 tid=0x00007fa52c070000 nid=0x5c73
runnable [0x00007fa51151b000]
java.lang.Thread.State: RUNNABLE
at java.nio.HeapByteBuffer.ix(HeapByteBuffer.java:131)
at java.nio.HeapByteBuffer.get(HeapByteBuffer.java:139)
at java.nio.ByteBuffer.hashCode(ByteBuffer.java:1083)
at java.util.Objects.hashCode(Objects.java:96)
at java.util.HashMap$Entry.hashCode(HashMap.java:847)
at java.util.AbstractMap.hashCode(AbstractMap.java:494)
at java.util.Objects.hashCode(Objects.java:96)
at java.util.HashMap$Entry.hashCode(HashMap.java:847)
at java.util.HashMap.hash(HashMap.java:362)
at java.util.HashMap.put(HashMap.java:492)
at java.util.HashSet.add(HashSet.java:217)
at
org.ofbiz.base.util.collections.MapContext.entrySet(MapContext.java:306)
at java.util.HashMap.putAll(HashMap.java:642)
at
org.ofbiz.widget.model.ModelFormField$ListOptions.addOptionValues(ModelFormField.java:2716)
at
org.ofbiz.widget.model.ModelFormField$FieldInfoWithOptions.getAllOptionValues(ModelFormField.java:1985)
at
org.ofbiz.widget.renderer.macro.MacroFormRenderer.renderDropDownField(MacroFormRenderer.java:747)
at
org.ofbiz.widget.model.ModelFormField$DropDownField.renderFieldString(ModelFormField.java:1739)
at
org.ofbiz.widget.model.ModelFormField.renderFieldString(ModelFormField.java:693)
at
org.ofbiz.widget.renderer.FormRenderer.renderSingleFormString(FormRenderer.java:1195)
at org.ofbiz.widget.renderer.FormRenderer.render(FormRenderer.java:261)
at
org.ofbiz.widget.model.ModelScreenWidget$Form.renderWidgetString(ModelScreenWidget.java:1052)
at
org.ofbiz.widget.renderer.macro.MacroScreenRenderer.renderScreenletSubWidget(MacroScreenRenderer.java:677)
at
org.ofbiz.widget.model.ModelScreenWidget$Screenlet.renderWidgetString(ModelScreenWidget.java:598)
at
org.ofbiz.widget.model.ModelScreenWidget.renderSubWidgetsString(ModelScreenWidget.java:98)
at
org.ofbiz.widget.model.ModelScreenWidget$Section.renderWidgetString(ModelScreenWidget.java:280)
at
org.ofbiz.widget.model.ModelScreen.renderScreenString(ModelScreen.java:164)
at
org.ofbiz.widget.model.ScreenFactory.renderReferencedScreen(ScreenFactory.java:211)
at
org.ofbiz.widget.model.ModelScreenWidget$IncludeScreen.renderWidgetString(ModelScreenWidget.java:779)
at
org.ofbiz.widget.model.ModelScreenWidget.renderSubWidgetsString(ModelScreenWidget.java:98)
at
org.ofbiz.widget.model.ModelScreenWidget$Container.renderWidgetString(ModelScreenWidget.java:459)
at
org.ofbiz.widget.model.ModelScreenWidget.renderSubWidgetsString(ModelScreenWidget.java:98)
at
org.ofbiz.widget.model.ModelScreenWidget$Section.renderWidgetString(ModelScreenWidget.java:280)
at
org.ofbiz.widget.model.ModelScreenWidget.renderSubWidgetsString(ModelScreenWidget.java:98)
at
org.ofbiz.widget.model.ModelScreenWidget$DecoratorSection.renderWidgetString(ModelScreenWidget.java:905)
at
org.ofbiz.widget.model.ModelScreenWidget$SectionsRenderer.render(ModelScreenWidget.java:127)
at
org.ofbiz.widget.model.ModelScreenWidget$DecoratorSectionInclude.renderWidgetString(ModelScreenWidget.java:942)
at
org.ofbiz.widget.model.ModelScreenWidget.renderSubWidgetsString(ModelScreenWidget.java:98)
at
org.ofbiz.widget.model.ModelScreenWidget$Section.renderWidgetString(ModelScreenWidget.java:280)
at
org.ofbiz.widget.model.ModelScreenWidget.renderSubWidgetsString(ModelScreenWidget.java:98)
at
org.ofbiz.widget.model.ModelScreenWidget$DecoratorSection.renderWidgetString(ModelScreenWidget.java:905)
at
org.ofbiz.widget.model.ModelScreenWidget$SectionsRenderer.render(ModelScreenWidget.java:127)
at
org.ofbiz.widget.model.ModelScreenWidget$DecoratorSectionInclude.renderWidgetString(ModelScreenWidget.java:942)
at
org.ofbiz.widget.model.ModelScreenWidget.renderSubWidgetsString(ModelScreenWidget.java:98)
at
org.ofbiz.widget.model.ModelScreenWidget$DecoratorSection.renderWidgetString(ModelScreenWidget.java:905)
at
org.ofbiz.widget.model.ModelScreenWidget$SectionsRenderer.render(ModelScreenWidget.java:127)
at
org.ofbiz.widget.model.ModelScreenWidget$DecoratorSectionInclude.renderWidgetString(ModelScreenWidget.java:942)
at
org.ofbiz.widget.model.ModelScreenWidget.renderSubWidgetsString(ModelScreenWidget.java:98)
at
org.ofbiz.widget.model.ModelScreenWidget$Container.renderWidgetString(ModelScreenWidget.java:459)
at
org.ofbiz.widget.model.ModelScreenWidget.renderSubWidgetsString(ModelScreenWidget.java:98)
at
org.ofbiz.widget.model.ModelScreenWidget$Section.renderWidgetString(ModelScreenWidget.java:280)
at
org.ofbiz.widget.model.ModelScreenWidget.renderSubWidgetsString(ModelScreenWidget.java:98)
at
org.ofbiz.widget.model.ModelScreenWidget$Container.renderWidgetString(ModelScreenWidget.java:459)
at
org.ofbiz.widget.model.ModelScreenWidget.renderSubWidgetsString(ModelScreenWidget.java:98)
at
org.ofbiz.widget.model.ModelScreenWidget$Container.renderWidgetString(ModelScreenWidget.java:459)
at
org.ofbiz.widget.model.ModelScreenWidget.renderSubWidgetsString(ModelScreenWidget.java:98)
at
org.ofbiz.widget.model.ModelScreenWidget$Section.renderWidgetString(ModelScreenWidget.java:280)
at
org.ofbiz.widget.model.ModelScreen.renderScreenString(ModelScreen.java:164)
at
org.ofbiz.widget.model.ScreenFactory.renderReferencedScreen(ScreenFactory.java:211)
at
org.ofbiz.widget.model.ModelScreenWidget$DecoratorScreen.renderWidgetString(ModelScreenWidget.java:859)
at
org.ofbiz.widget.model.ModelScreenWidget.renderSubWidgetsString(ModelScreenWidget.java:98)
at
org.ofbiz.widget.model.ModelScreenWidget$Section.renderWidgetString(ModelScreenWidget.java:280)
at
org.ofbiz.widget.model.ModelScreenWidget.renderSubWidgetsString(ModelScreenWidget.java:98)
at
org.ofbiz.widget.model.ModelScreenWidget$Section.renderWidgetString(ModelScreenWidget.java:280)
at
org.ofbiz.widget.model.ModelScreenWidget.renderSubWidgetsString(ModelScreenWidget.java:98)
at
org.ofbiz.widget.model.ModelScreenWidget$Section.renderWidgetString(ModelScreenWidget.java:280)
at
org.ofbiz.widget.model.ModelScreen.renderScreenString(ModelScreen.java:164)
at
org.ofbiz.widget.model.ScreenFactory.renderReferencedScreen(ScreenFactory.java:211)
at
org.ofbiz.widget.model.ModelScreenWidget$DecoratorScreen.renderWidgetString(ModelScreenWidget.java:859)
at
org.ofbiz.widget.model.ModelScreenWidget.renderSubWidgetsString(ModelScreenWidget.java:98)
at
org.ofbiz.widget.model.ModelScreenWidget$Section.renderWidgetString(ModelScreenWidget.java:280)
at
org.ofbiz.widget.model.ModelScreen.renderScreenString(ModelScreen.java:164)
at
org.ofbiz.widget.model.ScreenFactory.renderReferencedScreen(ScreenFactory.java:211)
at
org.ofbiz.widget.model.ModelScreenWidget$DecoratorScreen.renderWidgetString(ModelScreenWidget.java:859)
at
org.ofbiz.widget.model.ModelScreenWidget.renderSubWidgetsString(ModelScreenWidget.java:98)
at
org.ofbiz.widget.model.ModelScreenWidget$Section.renderWidgetString(ModelScreenWidget.java:280)
at
org.ofbiz.widget.model.ModelScreen.renderScreenString(ModelScreen.java:164)
at
org.ofbiz.widget.renderer.ScreenRenderer.render(ScreenRenderer.java:136)
at
org.ofbiz.widget.renderer.ScreenRenderer.render(ScreenRenderer.java:98)
at
org.ofbiz.widget.renderer.macro.MacroScreenViewHandler.render(MacroScreenViewHandler.java:157)
at
org.ofbiz.webapp.control.RequestHandler.renderView(RequestHandler.java:989)
at
org.ofbiz.webapp.control.RequestHandler.doRequest(RequestHandler.java:676)
at
org.ofbiz.webapp.control.ControlServlet.doGet(ControlServlet.java:221)
at
org.ofbiz.webapp.control.ControlServlet.doPost(ControlServlet.java:89)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:646)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
at
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
at
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at
org.ofbiz.webapp.control.ContextFilter.doFilter(ContextFilter.java:321)
at
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at
org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
at
org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
at
org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:503)
at
org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
at
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
at
org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
at
org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950)
at
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:421)
at org.apache.coyote.ajp.AjpProcessor.process(AjpProcessor.java:190)
at
org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:611)
at
org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:314)
- locked <0x00000006f95b1cf0> (a
org.apache.tomcat.util.net.SocketWrapper)
at
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at
org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
{noformat}
The solution would be not to use HashSet but instead a simpler Set class such
as a Set backed by a List.
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)