Bug #82203 com.mysql.fabric.HashShardMapping is not thread safe
Submitted: 12 Jul 2016 16:52 Modified: 8 Feb 2017 21:42
Reporter: Cosmin Mutu Email Updates:
Status: Closed Impact on me:
None 
Category:Connector / J Severity:S1 (Critical)
Version:5.1.39 OS:Any
Assigned to: Filipe Silva CPU Architecture:Any
Tags: connectorj, hash, HashShardMapping, safe, thread

[12 Jul 2016 16:52] Cosmin Mutu
Description:
If multiple threads require to have hashes computed for a key, then an ArrayIndexOutOfBoundsException is thrown by the md5Hasher static instance from inside the HashShardMapping
Exception in thread "Thread-0" java.lang.ArrayIndexOutOfBoundsException
	at java.lang.System.arraycopy(Native Method)
	at sun.security.provider.DigestBase.engineUpdate(Unknown Source)
	at java.security.MessageDigest$Delegate.engineUpdate(Unknown Source)
	at java.security.MessageDigest.update(Unknown Source)
	at java.security.MessageDigest.digest(Unknown Source)
-----------------------------------------------------------------------------
public class HashShardMapping extends ShardMapping {
  private static final MessageDigest md5Hasher;
  ... 
  protected ShardIndex getShardIndexForKey(String stringKey) {
    String hashedKey = new BigInteger(/* unsigned/positive */1, md5Hasher.digest(stringKey.getBytes())).toString(16).toUpperCase();
  } 
..
}

How to repeat:
Create a topology with a minimum of 2 shards, using HASH.

Using multiple threads, open one connection per thread from same FabricDataSource and try to perform INSERT operations, by setting the shardKey for each operation (becasue HASH was the selected algorithm for distributing the data on the shards then HashShardMapping will be called and above exception will occur).

Suggested fix:
Wrap the call to md5hasher instance with a synchronized block :

 String hashedKey = null;
        synchronized (md5Hasher) {
            hashedKey = new BigInteger(/* unsigned/positive */1, md5Hasher.digest(stringKey.getBytes())).toString(16).toUpperCase();
        }
[13 Jul 2016 17:23] Filipe Silva
Hi Cosmin Mutu,

Thank you for this bug report. It was verified as described.
[8 Feb 2017 21:42] Daniel So
Posted by developer:
 
Added the following entry to the Connector/J 5.1.41 changelog: 

"In a Fabric setup, when multiple threads required to have hashes computed, an ArrayIndexOutOfBoundsException might be thrown from inside HashShardMapping. This fix prevents the issue by having HashShardMapping.getShardIndexForKey() synchronized."