TObjectIntHashMap has problem with equals and hashcodes

Issue #36 new
Aleksey Linetskiy
created an issue

When adding a record to TObjectIntHashMap, I got the following error. Please note, that both strings are referring to the same object, and the hashCodes are, of course, the same.

Here is the code snippet where the error occurred : tags = new TObjectIntHashMap<String>(); scanner.nextLine(); while (scanner.hasNextLine()) { String str = scanner.nextLine().trim(); if(str.equals("")) { continue; } String[] tag = str.split(",");

            int start_of_str = 0;
            if(tag.length > 1 && tag[1].equalsIgnoreCase("TRUE"))
            {
                start_of_str = 1;
            }
            tags.put(tag[0], start_of_str);
            }

Stacktrace:

java.lang.IllegalArgumentException: Equal objects must have equal hashcodes. During rehashing, Trove discovered that the following two objects claim to be equal (as in java.lang.Object.equals()) but their hashCodes (or those calculated by your TObjectHashingStrategy) are not equal.This violates the general contract of java.lang.Object.hashCode(). See bullet point two in that method's documentation. object #1 =class java.lang.String id= 29669059 hashCode= -597802845 toString= user_agent=Mp3Bot; object #2 =class java.lang.String id= 29669059 hashCode= -597802845 toString= user_agent=Mp3Bot

            at gnu.trove.impl.hash.TObjectHash.buildObjectContractViolation(TObjectHash.java:464)
            at gnu.trove.impl.hash.TObjectHash.throwObjectContractViolation(TObjectHash.java:426)
            at gnu.trove.map.hash.TObjectIntHashMap.rehash(TObjectIntHashMap.java:191)
            at gnu.trove.impl.hash.THash.postInsertHook(THash.java:388)
            at gnu.trove.map.hash.TObjectIntHashMap.doPut(TObjectIntHashMap.java:265)
            at gnu.trove.map.hash.TObjectIntHashMap.put(TObjectIntHashMap.java:240)

Comments (17)

  1. Rob Eden

    This test case works with that file. Could you see if it works for you?

    public class Issue36Test {
        public static void main( String[] args ) throws Exception {
            Scanner scanner = new Scanner( new File( args[ 0 ] ) );
            TObjectIntHashMap<String> tags = new TObjectIntHashMap<>();
            scanner.nextLine();
            while ( scanner.hasNextLine() ) {
                String str = scanner.nextLine().trim();
                if ( str.equals( "" ) ) {
                    continue;
                }
                String[] tag = str.split( "," );
                int start_of_str = 0;
                if ( tag.length > 1 && tag[ 1 ].equalsIgnoreCase( "TRUE" ) ) {
                    start_of_str = 1;
                }
                tags.put( tag[ 0 ], start_of_str );
            }
    
            System.out.println( "Map size: " + tags.size() );
        }
    }
    
  2. Aleksey Linetskiy reporter

    The test case worked for me as well. The only difference was that I had to change one line:

    TObjectIntHashMap<String> tags = new TObjectIntHashMap<String>();

    Since we are building for Java 1.5 and the code won't compile otherwise. Not sure whether this is a relevant difference....

  3. Rob Eden

    We're unable to reproduce, but it's clearly an issue since the exception is citing the same (immutable) object. There must be a logic issue in there somewhere.

    I've escalated the severity, though it might be difficult to fix without a test case demonstrating the failure. I'll start by a general logic review.

  4. Martin NA

    I just hit this with a "normal" object:

    Caused by: java.lang.IllegalArgumentException: Equal objects must have equal hashcodes. During rehashing, Trove discovered that the following two objects claim to be equal (as in java.lang.Object.equals()) but their hashCodes (or those calculated by your TObjectHashingStrategy) are not equal.This violates the general contract of java.lang.Object.hashCode(). See bullet point two in that method's documentation.

    object #1 =class org.marsik.elshelves.backend.entities.Purchase id= 1853601219 hashCode= 340716350 toString= org.marsik.elshelves.backend.entities.Purchase{id=null, uuid=7a938348-6ae9-11e5-89fc-820f8dc8fba1}; object #2 =class org.marsik.elshelves.backend.entities.Purchase id= 1853601219 hashCode= 340716350 toString= org.marsik.elshelves.backend.entities.Purchase{id=null, uuid=7a938348-6ae9-11e5-89fc-820f8dc8fba1}

    Please note that is also cites the same hashCode for both objects. The object is mutable, but the hashCode only uses the uuid (which is identical as well). It is easy to reproduce, but hard to isolate as it happened during data restore with about a megabyte of data (it happens every time I try that though).

    The trove version was 3.0.3.

  5. Lee Harland

    Hi came across this thread when googling for a very similar error. Created a TObjectIntHashMap<String> and processing a large amount of data and can reproduce this consistently; unfortunately no matter how hard i try i cant make a unit test that fails, i only see it when i'm running our proprietary and very large codebase so at present i'm unable to ship any test case (i have done as much as i could to try to "break" trove and so far not managed it). I guess if there is anything i can debug i'm happy to run my script again if there's anything i can do. [Other than this trove is marvellous].

    java.lang.IllegalArgumentException: Equal objects must have equal hashcodes. During rehashing, Trove discovered that the following two objects claim to be equal (as in java.lang.Object.equals()) but their hashCodes (or those calculated by your TObjectHashingStrategy) are not equal.This violates the general contract of java.lang.Object.hashCode(). See bullet point two in that method's documentation. object #1 =class java.lang.String id= 891529619 hashCode= 947736095 toString= #document/gtr:project/gtr:publications/gtr:publication/gtr:id; object #2 =class java.lang.String id= 1005384738 hashCode= 947736095 toString= #document/gtr:project/gtr:publications/gtr:publication/gtr:id

    at gnu.trove.impl.hash.TObjectHash.buildObjectContractViolation(TObjectHash.java:464)
    at gnu.trove.impl.hash.TObjectHash.throwObjectContractViolation(TObjectHash.java:426)
    at gnu.trove.map.hash.TObjectByteHashMap.rehash(TObjectByteHashMap.java:191)
    at gnu.trove.impl.hash.THash.postInsertHook(THash.java:388)
    at gnu.trove.map.hash.TObjectByteHashMap.doPut(TObjectByteHashMap.java:265)
    at gnu.trove.map.hash.TObjectByteHashMap.put(TObjectByteHashMap.java:240)
    

    It is running in a multi-threaded app but the instance itself is confined to a single thread so its not a simple concurrency issue (although i obviously dont know what could be going on deep down).

    Thanks

  6. Log in to comment