diff --git a/hibernate-core/src/main/java/org/hibernate/cache/internal/BasicCacheKeyImplementation.java b/hibernate-core/src/main/java/org/hibernate/cache/internal/BasicCacheKeyImplementation.java index 7f327b1d4070..c2e01d555d45 100644 --- a/hibernate-core/src/main/java/org/hibernate/cache/internal/BasicCacheKeyImplementation.java +++ b/hibernate-core/src/main/java/org/hibernate/cache/internal/BasicCacheKeyImplementation.java @@ -55,7 +55,16 @@ public BasicCacheKeyImplementation( } private static int calculateHashCode(Object disassembledKey, Type type) { - return type.getHashCode( disassembledKey ); + return hash( type.getHashCode( disassembledKey ) ); + } + + @Internal + public static int hash(int h) { + // Mix the result with the Murmur3 finalising function + h = (h ^ (h >>> 16)) * 0x85ebca6b; + h = (h ^ (h >>> 13)) * 0xc2b2ae35; + h = h ^ (h >>> 16); + return h; } public Object getId() { diff --git a/hibernate-core/src/main/java/org/hibernate/cache/internal/CacheKeyImplementation.java b/hibernate-core/src/main/java/org/hibernate/cache/internal/CacheKeyImplementation.java index dd1d7371c855..69e3ff989acd 100644 --- a/hibernate-core/src/main/java/org/hibernate/cache/internal/CacheKeyImplementation.java +++ b/hibernate-core/src/main/java/org/hibernate/cache/internal/CacheKeyImplementation.java @@ -81,7 +81,7 @@ public CacheKeyImplementation( private static int calculateHashCode(Object id, Type type, String tenantId) { int result = type.getHashCode( id ); result = 31 * result + ( tenantId != null ? tenantId.hashCode() : 0 ); - return result; + return BasicCacheKeyImplementation.hash( result ); } public Object getId() { diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/caching/mocked/CacheKeyImplementationHashCodeTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/caching/mocked/CacheKeyImplementationHashCodeTest.java index 9c2c0810aec3..8d82e85fe94f 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/caching/mocked/CacheKeyImplementationHashCodeTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/caching/mocked/CacheKeyImplementationHashCodeTest.java @@ -13,7 +13,6 @@ import org.hibernate.boot.Metadata; import org.hibernate.boot.MetadataSources; import org.hibernate.boot.SessionFactoryBuilder; -import org.hibernate.cache.internal.CacheKeyImplementation; import org.hibernate.cache.internal.DefaultCacheKeysFactory; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.persister.entity.EntityPersister; @@ -24,6 +23,7 @@ import org.junit.Test; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; /** * @author Gail Badner @@ -32,37 +32,74 @@ public class CacheKeyImplementationHashCodeTest { @Test @JiraKey( value = "HHH-12746") - public void test() { + public void testHashCodeChanges() { try (ServiceRegistryImplementor serviceRegistry = ServiceRegistryUtil.serviceRegistry()) { MetadataSources ms = new MetadataSources( serviceRegistry ); ms.addAnnotatedClass( AnEntity.class ).addAnnotatedClass( AnotherEntity.class ); Metadata metadata = ms.buildMetadata(); final SessionFactoryBuilder sfb = metadata.getSessionFactoryBuilder(); try ( SessionFactoryImplementor sessionFactory = (SessionFactoryImplementor) sfb.build()) { - CacheKeyImplementation anEntityCacheKey = createCacheKeyImplementation( + Object anEntityCacheKey = createCacheKeyImplementation( 1, sessionFactory.getRuntimeMetamodels() .getMappingMetamodel() .getEntityDescriptor( AnEntity.class ), - sessionFactory + sessionFactory, + "tenant" ); - CacheKeyImplementation anotherEntityCacheKey = createCacheKeyImplementation( + Object anotherEntityCacheKey = createCacheKeyImplementation( 1, sessionFactory.getRuntimeMetamodels() .getMappingMetamodel() .getEntityDescriptor( AnotherEntity.class ), - sessionFactory + sessionFactory, + "tenant" ); assertFalse( anEntityCacheKey.equals( anotherEntityCacheKey ) ); } } } - private CacheKeyImplementation createCacheKeyImplementation( + @Test + @JiraKey( value = "HHH-19218") + public void testMixedHashCode() { + try (ServiceRegistryImplementor serviceRegistry = ServiceRegistryUtil.serviceRegistry()) { + MetadataSources ms = new MetadataSources( serviceRegistry ); + ms.addAnnotatedClass( AnEntity.class ).addAnnotatedClass( AnotherEntity.class ); + Metadata metadata = ms.buildMetadata(); + final SessionFactoryBuilder sfb = metadata.getSessionFactoryBuilder(); + try ( SessionFactoryImplementor sessionFactory = (SessionFactoryImplementor) sfb.build()) { + Object anEntityCacheKey = createCacheKeyImplementation( + 1, + sessionFactory.getRuntimeMetamodels() + .getMappingMetamodel() + .getEntityDescriptor( AnEntity.class ), + sessionFactory, + null + ); + assertTrue( (anEntityCacheKey.hashCode() >>> 16) != 0 ); + assertTrue( (anEntityCacheKey.hashCode() << 16) != 0 ); + + Object anotherEntityCacheKey = createCacheKeyImplementation( + 1, + sessionFactory.getRuntimeMetamodels() + .getMappingMetamodel() + .getEntityDescriptor( AnotherEntity.class ), + sessionFactory, + "0" + ); + assertTrue( (anotherEntityCacheKey.hashCode() >>> 16) != 0 ); + assertTrue( (anotherEntityCacheKey.hashCode() << 16) != 0 ); + } + } + } + + private Object createCacheKeyImplementation( int id, EntityPersister persister, - SessionFactoryImplementor sfi) { - return (CacheKeyImplementation) DefaultCacheKeysFactory.staticCreateEntityKey( id, persister, sfi, "tenant" ); + SessionFactoryImplementor sfi, + String tenantIdentifier) { + return DefaultCacheKeysFactory.staticCreateEntityKey( id, persister, sfi, tenantIdentifier); } @Entity(name = "AnEntity") diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/querycache/QueryRestrictedCollectionCachingTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/querycache/QueryRestrictedCollectionCachingTests.java index c5f577ff1747..411bf96bd698 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/querycache/QueryRestrictedCollectionCachingTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/querycache/QueryRestrictedCollectionCachingTests.java @@ -131,7 +131,7 @@ private static Serializable[] extractCachedCollectionKeys(CacheImplementor cache final CollectionReadWriteAccess authorsRegionAccess = (CollectionReadWriteAccess) cache.getCollectionRegionAccess( navigableRole ); final MapStorageAccessImpl storageAccess = (MapStorageAccessImpl) authorsRegionAccess.getStorageAccess(); - final BasicCacheKeyImplementation cacheKey = new BasicCacheKeyImplementation( ownerKey, role, ownerKey ); + final BasicCacheKeyImplementation cacheKey = new BasicCacheKeyImplementation( ownerKey, role, BasicCacheKeyImplementation.hash( ownerKey ) ); final AbstractReadWriteAccess.Item cacheItem = (AbstractReadWriteAccess.Item) storageAccess.getFromData( cacheKey ); assertThat( cacheItem ).isNotNull();