[ 
https://issues.apache.org/jira/browse/OFBIZ-6621?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Michael Brohl updated OFBIZ-6621:
---------------------------------
    Fix Version/s:     (was: Release Branch 14.12)
                   14.12.01

> 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: Release Branch 14.12, Upcoming Branch
>            Reporter: Gareth Carter
>            Assignee: Michael Brohl
>            Priority: Critical
>             Fix For: 14.12.01, Upcoming Branch
>
>         Attachments: MapContext-v2.patch, MapContext.patch
>
>
> 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)

Reply via email to