JDK-8203190 : SessionId.hashCode generates too many collisions
  • Type: Enhancement
  • Component: security-libs
  • Sub-Component: javax.net.ssl
  • Affected Version: 7,8,9,10
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2018-05-14
  • Updated: 2020-07-28
  • Resolved: 2018-12-07
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 7 JDK 8 Other
7u211Fixed 8u192Fixed openjdk7uFixed
Related Reports
Duplicate :  
Description
A DESCRIPTION OF THE PROBLEM :
The implementation of hashCode() in sun.security.ssl.SessionId generates many collisions.
The SslEngine of Oracle has an HashMap of SessionId, and because the hashCode generates many collisions the HashMap gets really slow due to the conversion from List to a Tree of a bucket.

This issue was discovered by studying the following stacktrace:
   java.lang.Thread.State: RUNNABLE
	at java.util.HashMap$TreeNode.find(HashMap.java:1878)
	at java.util.HashMap$TreeNode.find(HashMap.java:1874)
	at java.util.HashMap$TreeNode.find(HashMap.java:1874)
	at java.util.HashMap$TreeNode.find(HashMap.java:1874)
	at java.util.HashMap$TreeNode.find(HashMap.java:1874)
	at java.util.HashMap$TreeNode.find(HashMap.java:1874)
	at java.util.HashMap$TreeNode.getTreeNode(HashMap.java:1886)
	at java.util.HashMap.removeNode(HashMap.java:824)
	at java.util.HashMap.remove(HashMap.java:799)
	at sun.security.util.MemoryCache.emptyQueue(Cache.java:299)
	at sun.security.util.MemoryCache.get(Cache.java:386)

The MemoryCache class is synchronised and because the HashMap gets really inefficient, many threads were blocked waiting for this class.

The current hashCode implementation is very inefficient, If you generates 10M random SessionId of 32bytes, you can have more than 10K elements with the same hashCode.
The current implementation sum an array of 32 bytes (maximum), which is very similar to the concept of the "probability of 2 dice": http://statweb.stanford.edu/~susan/courses/s60/split/node65.html
Current SessionId.hashCode() implementation:
        for (byte element : a)
            result +=element;

A better implementation of the hashCode for a byte array is the one in Arrays.hashCode(byte[]), that for 10M random SessionId of 32byte collides only 2/3 times maximum for the same hashCode.



Comments
Fix Request (OpenJDK 8u): webrev: http://cr.openjdk.java.net/~sgehwolf/webrevs/JDK-8203190/01/webrev/ Please approve this fix to SessionId.hashCode() so as to reduce collisions when many sessions get added to MemoryCache which uses a LinkedHashMap internally. There is no functional change. Merely the implementation of hashCode() changes to use Arrays.hashCode() which has shown to produce less collisions and, thus, reduces elements in trees used for collision resolution. See linked RFR above. Testing: checked collisions are indeed reduced. Risk seems minimal. The fix has been reviewed by Andrew Hughes and Aleksey Shipilev.
17-05-2019

OpenJDK 8u RFR: http://mail.openjdk.java.net/pipermail/jdk8u-dev/2019-May/009345.html
16-05-2019

Yes, I was planning on doing this today. Not sure about a test case. I'll look into it.
16-05-2019

Are you planning to post this to the mailing list for review? Any possibility of a test case?
15-05-2019

I'll work on an OpenJDK 8u backport for this. Candiate webrev: http://cr.openjdk.java.net/~sgehwolf/webrevs/JDK-8203190/01/webrev/
15-05-2019