[ 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)