HHH-11356 - Adjust the 2nd-Cache SPIs to better reflect supported uses

Adding tests on 5.2 branch asserting specific expectations of Cache and Statistics API and SPI to ensure we maintain seamless upgradeability to 5.3 in terms of region name expectations (region-name-prefix  handling)

* RegionNameTest - old API/SPI methods expected prefixed region name - make sure we continue to support that
* ConcurrentStatisticsTest - added cache prefix
* RefreshUpdatedDataTest - removed inaccurate assertions
This commit is contained in:
Steve Ebersole 2018-03-13 17:51:00 -05:00
parent 097112353e
commit 0c7e29b4d3
3 changed files with 60 additions and 150 deletions

View File

@ -7,6 +7,8 @@
package org.hibernate.stat.internal; package org.hibernate.stat.internal;
import org.hibernate.SessionFactory; import org.hibernate.SessionFactory;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.cfg.Configuration;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
@ -34,6 +36,13 @@ public class ConcurrentStatisticsTest extends BaseCoreFunctionalTestCase {
statistics = new ConcurrentStatisticsImpl( (SessionFactoryImplementor) sessionFactory ); statistics = new ConcurrentStatisticsImpl( (SessionFactoryImplementor) sessionFactory );
} }
@Override
protected void configure(Configuration configuration) {
super.configure( configuration );
configuration.setProperty( AvailableSettings.CACHE_REGION_PREFIX, "my-app" );
}
@After @After
public void tearDown() { public void tearDown() {
sessionFactory.close(); sessionFactory.close();

View File

@ -41,8 +41,6 @@ public class RefreshUpdatedDataTest extends BaseCoreFunctionalTestCase {
return new Class[] { return new Class[] {
ReadWriteCacheableItem.class, ReadWriteCacheableItem.class,
ReadWriteVersionedCacheableItem.class, ReadWriteVersionedCacheableItem.class,
NonStrictReadWriteCacheableItem.class,
NonStrictReadWriteVersionedCacheableItem.class,
}; };
} }
@ -77,16 +75,6 @@ public class RefreshUpdatedDataTest extends BaseCoreFunctionalTestCase {
readWriteVersionedCacheableItem.getTags().add( "ORM" ); readWriteVersionedCacheableItem.getTags().add( "ORM" );
s.persist( readWriteVersionedCacheableItem ); s.persist( readWriteVersionedCacheableItem );
NonStrictReadWriteCacheableItem nonStrictReadWriteCacheableItem = new NonStrictReadWriteCacheableItem( BEFORE );
nonStrictReadWriteCacheableItem.getTags().add( "Hibernate" );
nonStrictReadWriteCacheableItem.getTags().add( "ORM" );
s.persist( nonStrictReadWriteCacheableItem );
NonStrictReadWriteVersionedCacheableItem nonStrictReadWriteVersionedCacheableItem = new NonStrictReadWriteVersionedCacheableItem( BEFORE );
nonStrictReadWriteVersionedCacheableItem.getTags().add( "Hibernate" );
nonStrictReadWriteVersionedCacheableItem.getTags().add( "ORM" );
s.persist( nonStrictReadWriteVersionedCacheableItem );
s.getTransaction().commit(); s.getTransaction().commit();
s.close(); s.close();
@ -103,28 +91,14 @@ public class RefreshUpdatedDataTest extends BaseCoreFunctionalTestCase {
readWriteVersionedCacheableItem1.setName( AFTER ); readWriteVersionedCacheableItem1.setName( AFTER );
readWriteVersionedCacheableItem1.getTags().remove("ORM"); readWriteVersionedCacheableItem1.getTags().remove("ORM");
NonStrictReadWriteCacheableItem nonStrictReadWriteCacheableItem1 = s1.get( NonStrictReadWriteCacheableItem.class, nonStrictReadWriteCacheableItem.getId() );
nonStrictReadWriteCacheableItem1.setName( AFTER );
nonStrictReadWriteCacheableItem1.getTags().remove("ORM");
NonStrictReadWriteVersionedCacheableItem nonStrictReadWriteVersionedCacheableItem1 = s1.get( NonStrictReadWriteVersionedCacheableItem.class, nonStrictReadWriteVersionedCacheableItem.getId() );
nonStrictReadWriteVersionedCacheableItem1.setName( AFTER );
nonStrictReadWriteVersionedCacheableItem1.getTags().remove("ORM");
s1.flush(); s1.flush();
s1.refresh( readWriteCacheableItem1 ); s1.refresh( readWriteCacheableItem1 );
s1.refresh( readWriteVersionedCacheableItem1 ); s1.refresh( readWriteVersionedCacheableItem1 );
s1.refresh( nonStrictReadWriteCacheableItem1 );
s1.refresh( nonStrictReadWriteVersionedCacheableItem1 );
assertEquals( AFTER, readWriteCacheableItem1.getName() ); assertEquals( AFTER, readWriteCacheableItem1.getName() );
assertEquals( 1, readWriteCacheableItem1.getTags().size() ); assertEquals( 1, readWriteCacheableItem1.getTags().size() );
assertEquals( AFTER, readWriteVersionedCacheableItem1.getName() ); assertEquals( AFTER, readWriteVersionedCacheableItem1.getName() );
assertEquals( 1, readWriteVersionedCacheableItem1.getTags().size() ); assertEquals( 1, readWriteVersionedCacheableItem1.getTags().size() );
assertEquals( AFTER, nonStrictReadWriteCacheableItem1.getName() );
assertEquals( 1, nonStrictReadWriteCacheableItem1.getTags().size() );
assertEquals( AFTER, nonStrictReadWriteVersionedCacheableItem1.getName() );
assertEquals( 1, nonStrictReadWriteVersionedCacheableItem1.getTags().size() );
// open another session // open another session
Session s2 = sessionFactory().openSession(); Session s2 = sessionFactory().openSession();
@ -132,21 +106,12 @@ public class RefreshUpdatedDataTest extends BaseCoreFunctionalTestCase {
s2.beginTransaction(); s2.beginTransaction();
ReadWriteCacheableItem readWriteCacheableItem2 = s2.get( ReadWriteCacheableItem.class, readWriteCacheableItem.getId() ); ReadWriteCacheableItem readWriteCacheableItem2 = s2.get( ReadWriteCacheableItem.class, readWriteCacheableItem.getId() );
ReadWriteVersionedCacheableItem readWriteVersionedCacheableItem2 = s2.get( ReadWriteVersionedCacheableItem.class, readWriteVersionedCacheableItem.getId() ); ReadWriteVersionedCacheableItem readWriteVersionedCacheableItem2 = s2.get( ReadWriteVersionedCacheableItem.class, readWriteVersionedCacheableItem.getId() );
NonStrictReadWriteCacheableItem nonStrictReadWriteCacheableItem2 = s2.get( NonStrictReadWriteCacheableItem.class, nonStrictReadWriteCacheableItem.getId() );
NonStrictReadWriteVersionedCacheableItem nonStrictReadWriteVersionedCacheableItem2 = s2.get( NonStrictReadWriteVersionedCacheableItem.class, nonStrictReadWriteVersionedCacheableItem.getId() );
assertEquals( BEFORE, readWriteCacheableItem2.getName() ); assertEquals( BEFORE, readWriteCacheableItem2.getName() );
assertEquals( 2, readWriteCacheableItem2.getTags().size() ); assertEquals( 2, readWriteCacheableItem2.getTags().size() );
assertEquals( BEFORE, readWriteVersionedCacheableItem2.getName() ); assertEquals( BEFORE, readWriteVersionedCacheableItem2.getName() );
assertEquals( 2, readWriteVersionedCacheableItem2.getTags().size() ); assertEquals( 2, readWriteVersionedCacheableItem2.getTags().size() );
//READ_UNCOMMITTED because there is no locking to prevent collections from being cached in the first Session
assertEquals( BEFORE, nonStrictReadWriteCacheableItem2.getName() );
assertEquals( 1, nonStrictReadWriteCacheableItem2.getTags().size());
assertEquals( BEFORE, nonStrictReadWriteVersionedCacheableItem2.getName() );
assertEquals( 1, nonStrictReadWriteVersionedCacheableItem2.getTags().size() );
s2.getTransaction().commit(); s2.getTransaction().commit();
} }
finally { finally {
@ -163,8 +128,6 @@ public class RefreshUpdatedDataTest extends BaseCoreFunctionalTestCase {
s.beginTransaction(); s.beginTransaction();
s.delete( readWriteCacheableItem ); s.delete( readWriteCacheableItem );
s.delete( readWriteVersionedCacheableItem ); s.delete( readWriteVersionedCacheableItem );
s.delete( nonStrictReadWriteCacheableItem );
s.delete( nonStrictReadWriteVersionedCacheableItem );
s.getTransaction().commit(); s.getTransaction().commit();
s.close(); s.close();
} }
@ -255,91 +218,4 @@ public class RefreshUpdatedDataTest extends BaseCoreFunctionalTestCase {
return tags; return tags;
} }
} }
@Entity(name = "NonStrictReadWriteCacheableItem")
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE, region = "item")
public static class NonStrictReadWriteCacheableItem {
@Id
@GeneratedValue
private Long id;
private String name;
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
@ElementCollection
private List<String> tags = new ArrayList<>();
public NonStrictReadWriteCacheableItem() {
}
public NonStrictReadWriteCacheableItem(String name) {
this.name = name;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<String> getTags() {
return tags;
}
}
@Entity(name = "NonStrictReadWriteVersionedCacheableItem")
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE, region = "item")
public static class NonStrictReadWriteVersionedCacheableItem {
@Id
@GeneratedValue
private Long id;
private String name;
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
@ElementCollection
private List<String> tags = new ArrayList<>();
@Version
private int version;
public NonStrictReadWriteVersionedCacheableItem() {
}
public NonStrictReadWriteVersionedCacheableItem(String name) {
this.name = name;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<String> getTags() {
return tags;
}
}
} }

View File

@ -21,6 +21,7 @@ import org.hibernate.annotations.NaturalIdCache;
import org.hibernate.boot.MetadataSources; import org.hibernate.boot.MetadataSources;
import org.hibernate.cfg.AvailableSettings; import org.hibernate.cfg.AvailableSettings;
import org.hibernate.engine.spi.CacheImplementor; import org.hibernate.engine.spi.CacheImplementor;
import org.hibernate.internal.util.compare.EqualsHelper;
import org.hibernate.stat.NaturalIdCacheStatistics; import org.hibernate.stat.NaturalIdCacheStatistics;
import org.hibernate.stat.SecondLevelCacheStatistics; import org.hibernate.stat.SecondLevelCacheStatistics;
import org.hibernate.stat.Statistics; import org.hibernate.stat.Statistics;
@ -29,6 +30,9 @@ import org.hibernate.stat.spi.StatisticsImplementor;
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
import org.junit.Test; import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
/** /**
* Test API and SPI expectation wrt region names - whether they expect the * Test API and SPI expectation wrt region names - whether they expect the
* prefixed or un-prefixed name * prefixed or un-prefixed name
@ -43,11 +47,13 @@ public class RegionNameTest extends BaseNonConfigCoreFunctionalTestCase {
} }
private final String cachePrefix = "app1"; private final String cachePrefix = "app1";
private final String localName = "a.b.c";
@Override @Override
protected void addSettings(Map settings) { protected void addSettings(Map settings) {
super.addSettings( settings ); super.addSettings( settings );
settings.put( AvailableSettings.USE_SECOND_LEVEL_CACHE, "true" ); settings.put( AvailableSettings.USE_SECOND_LEVEL_CACHE, "true" );
settings.put( AvailableSettings.USE_QUERY_CACHE, "true" );
settings.put( AvailableSettings.CACHE_REGION_PREFIX, cachePrefix ); settings.put( AvailableSettings.CACHE_REGION_PREFIX, cachePrefix );
settings.put( AvailableSettings.GENERATE_STATISTICS, "true" ); settings.put( AvailableSettings.GENERATE_STATISTICS, "true" );
settings.put( AvailableSettings.HBM2DDL_AUTO, "create-drop" ); settings.put( AvailableSettings.HBM2DDL_AUTO, "create-drop" );
@ -57,14 +63,13 @@ public class RegionNameTest extends BaseNonConfigCoreFunctionalTestCase {
// todo (6.0) : same ^^, maintain API compatibility // todo (6.0) : same ^^, maintain API compatibility
@Test @Test
public void testStatsApi() { public void testLegacyStatsApi() {
//this needs to be the prefixed name :( // these references need to be the prefixed name
//final String regionName = "a.b.c"; final String regionName = cachePrefix + '.' + localName;
final String regionName = cachePrefix + ".a.b.c";
final Statistics stats = sessionFactory().getStatistics(); final Statistics stats = sessionFactory().getStatistics();
final SecondLevelCacheStatistics secondLevelCacheStatistics = stats.getSecondLevelCacheStatistics( regionName); final SecondLevelCacheStatistics secondLevelCacheStatistics = stats.getSecondLevelCacheStatistics( regionName );
assert secondLevelCacheStatistics != null; assert secondLevelCacheStatistics != null;
final NaturalIdCacheStatistics naturalIdCacheStatistics = stats.getNaturalIdCacheStatistics( regionName ); final NaturalIdCacheStatistics naturalIdCacheStatistics = stats.getNaturalIdCacheStatistics( regionName );
@ -75,14 +80,14 @@ public class RegionNameTest extends BaseNonConfigCoreFunctionalTestCase {
// todo (6.0) : same ^^, maintain API compatibility // todo (6.0) : same ^^, maintain API compatibility
@Test @Test
public void testStatsSpi() { public void testLegacyStatsSpi() {
//this needs to be the prefixed name :( // these need to be the prefixed name
//final String regionName = "a.b.c"; final String regionName = cachePrefix + '.' + localName;
final String regionName = cachePrefix + ".a.b.c";
final StatisticsImplementor statistics = sessionFactory().getStatistics(); final StatisticsImplementor statistics = sessionFactory().getStatistics();
statistics.clear();
statistics.naturalIdCacheHit(regionName); statistics.naturalIdCacheHit( regionName );
statistics.naturalIdCacheMiss( regionName ); statistics.naturalIdCacheMiss( regionName );
statistics.naturalIdCachePut( regionName ); statistics.naturalIdCachePut( regionName );
@ -90,36 +95,56 @@ public class RegionNameTest extends BaseNonConfigCoreFunctionalTestCase {
statistics.secondLevelCacheMiss( regionName ); statistics.secondLevelCacheMiss( regionName );
statistics.secondLevelCachePut( regionName ); statistics.secondLevelCachePut( regionName );
statistics.getNaturalIdCacheStatistics( regionName );
// stats for queries cannot be accessed second level cache regions map // stats for queries cannot be accessed second level cache regions map
// final String queryString = "select p from Person p"; final String queryString = "select p from Person p";
// final String queryCacheRegionName = "x.y.z"; final String queryCacheRegionName = "x.y.z";
// final String prefixedQueryCacheRegionName = cachePrefix + '.' + queryCacheRegionName;
// inTransaction(
// session -> session.createQuery( queryString ).setCacheable( true ).setCacheRegion( queryCacheRegionName ).list() inTransaction(
// ); // Only way to generate query region (to be accessible via stats) is to execute the query
// // note that session -> session.createQuery( queryString ).setCacheable( true ).setCacheRegion( queryCacheRegionName ).list()
// statistics.queryCacheHit( "select ...", queryCacheRegionName ); );
// statistics.queryCacheMiss( "select ...", queryCacheRegionName );
// statistics.queryCachePut( "select ...", queryCacheRegionName ); final SecondLevelCacheStatistics queryCacheStats = statistics.getSecondLevelCacheStatistics( regionName );
assert queryCacheStats != null;
// note that
statistics.queryCacheHit( queryString, prefixedQueryCacheRegionName );
statistics.queryCacheMiss( queryString, prefixedQueryCacheRegionName );
statistics.queryCachePut( queryString, prefixedQueryCacheRegionName );
// sessionFactory().getCache().evictQueryRegions();
} }
@Test @Test
public void testCacheSpi() { public void testLegacyCacheSpi() {
//this needs to be the prefixed name :( // these need to be the prefixed name
//final String regionName = "a.b.c"; final String regionName = cachePrefix + '.' + localName;
final String regionName = cachePrefix + ".a.b.c";
final CacheImplementor cache = sessionFactory().getCache(); final CacheImplementor cache = sessionFactory().getCache();
// just like stats, the cache for queries cannot be accessed second level cache regions map // just like stats, the cache for queries cannot be accessed second level cache regions map
assert cache.getSecondLevelCacheRegionNames().length == 1; assertEquals( 2, cache.getSecondLevelCacheRegionNames().length );
assert cache.getSecondLevelCacheRegionNames()[0].equals( regionName );
boolean foundRegion = false;
for ( String name : cache.getSecondLevelCacheRegionNames() ) {
if ( EqualsHelper.areEqual( name, regionName ) ) {
foundRegion = true;
break;
}
}
if ( !foundRegion ) {
fail( "Could not find region [" + regionName + "] in reported list of region names" );
}
assert cache.getEntityRegionAccess( regionName ) != null; assert cache.getEntityRegionAccess( regionName ) != null;
assert cache.getNaturalIdCacheRegionAccessStrategy( regionName ) != null; assert cache.getNaturalIdCacheRegionAccessStrategy( regionName ) != null;
assert cache.getCollectionRegionAccess(regionName ) != null; assert cache.getCollectionRegionAccess(regionName ) != null;
} }
@Entity( name = "Person" ) @Entity( name = "Person" )
@Table( name = "persons" ) @Table( name = "persons" )
@Cacheable @Cacheable