Skip to content

Commit 916849a

Browse files
committed
HHH-14691 Small optimisation for updating Query Cache Statistics
1 parent e919019 commit 916849a

File tree

3 files changed

+79
-24
lines changed

3 files changed

+79
-24
lines changed

hibernate-core/src/main/java/org/hibernate/stat/internal/StatisticsImpl.java

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -563,24 +563,21 @@ public CacheRegionStatisticsImpl getDomainDataRegionStatistics(String regionName
563563
}
564564

565565
@Override
566-
public CacheRegionStatisticsImpl getQueryRegionStatistics(String regionName) {
567-
final CacheRegionStatisticsImpl existing = l2CacheStatsMap.get( regionName );
568-
if ( existing != null ) {
569-
return existing;
570-
}
566+
public CacheRegionStatisticsImpl getQueryRegionStatistics(final String regionName) {
567+
return l2CacheStatsMap.getOrCompute( regionName, this::computeQueryRegionStatistics );
568+
}
571569

572-
final QueryResultsCache regionAccess = cache
573-
.getQueryResultsCacheStrictly( regionName );
570+
private CacheRegionStatisticsImpl computeQueryRegionStatistics(final String regionName) {
571+
final QueryResultsCache regionAccess = cache.getQueryResultsCacheStrictly( regionName );
574572
if ( regionAccess == null ) {
575-
return null;
573+
return null; //this null value will be cached
574+
}
575+
else {
576+
return new CacheRegionStatisticsImpl( regionAccess.getRegion() );
576577
}
577-
578-
return l2CacheStatsMap.getOrCompute(
579-
regionName,
580-
s -> new CacheRegionStatisticsImpl( regionAccess.getRegion() )
581-
);
582578
}
583579

580+
584581
@Override
585582
public CacheRegionStatisticsImpl getCacheRegionStatistics(String regionName) {
586583
if ( ! secondLevelCacheEnabled ) {

hibernate-core/src/main/java/org/hibernate/stat/internal/StatsNamedContainer.java

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@
2525
*/
2626
final class StatsNamedContainer<V> {
2727

28-
private final ConcurrentMap<String,V> map;
28+
private final ConcurrentMap<String,Object> map;
29+
private final static Object NULL_TOKEN = new Object();
2930

3031
/**
3132
* Creates a bounded container - based on BoundedConcurrentHashMap
@@ -63,33 +64,39 @@ public String[] keysAsArray() {
6364
* sure the function is invoked at most once: we don't need this guarantee, and prefer to reduce risk of blocking.
6465
*/
6566
public V getOrCompute(final String key, final Function<String, V> function) {
66-
final V v1 = map.get( key );
67+
final Object v1 = map.get( key );
6768
if ( v1 != null ) {
68-
return v1;
69+
if ( v1 == NULL_TOKEN ) {
70+
return null;
71+
}
72+
return (V) v1;
6973
}
7074
else {
7175
final V v2 = function.apply( key );
72-
//Occasionally a function might return null. We can't store a null in the CHM,
73-
// so a placeholder would be required to implement that, but we prefer to just keep this
74-
// situation as slightly sub-optimal so to not make the code more complex just to handle the exceptional case:
75-
// null values are assumed to be rare enough for this not being worth it.
7676
if ( v2 == null ) {
77+
map.put( key, NULL_TOKEN );
7778
return null;
7879
}
7980
else {
80-
final V v3 = map.putIfAbsent( key, v2 );
81+
final Object v3 = map.putIfAbsent( key, v2 );
8182
if ( v3 == null ) {
8283
return v2;
8384
}
8485
else {
85-
return v3;
86+
return (V) v3;
8687
}
8788
}
8889
}
8990
}
9091

9192
public V get(final String key) {
92-
return map.get( key );
93+
final Object o = map.get( key );
94+
if ( o == NULL_TOKEN) {
95+
return null;
96+
}
97+
else {
98+
return (V) o;
99+
}
93100
}
94101

95102
}

hibernate-core/src/test/java/org/hibernate/stat/internal/StatsNamedContainerNullComputedValueTest.java

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,21 @@
66
*/
77
package org.hibernate.stat.internal;
88

9+
import java.util.concurrent.atomic.AtomicInteger;
10+
911
import org.hibernate.testing.TestForIssue;
12+
import org.junit.Assert;
1013
import org.junit.Test;
1114

15+
import static org.junit.Assert.assertArrayEquals;
1216
import static org.junit.Assert.assertNull;
1317

1418
@TestForIssue(jiraKey = "HHH-13645")
1519
public class StatsNamedContainerNullComputedValueTest {
1620

21+
private final static AtomicInteger invocationCounterNullProducer = new AtomicInteger();
22+
private final static AtomicInteger invocationCounterValueProducer = new AtomicInteger();
23+
1724
@Test
1825
public void testNullComputedValue() {
1926
final StatsNamedContainer statsNamedContainer = new StatsNamedContainer<Integer>();
@@ -27,4 +34,48 @@ public void testNullComputedValue() {
2734
);
2835
}
2936

30-
}
37+
@Test
38+
public void abletoStoreNullValues() {
39+
final StatsNamedContainer statsNamedContainer = new StatsNamedContainer<Integer>();
40+
Assert.assertEquals( 0, invocationCounterNullProducer.get() );
41+
assertNull( getCacheWithNullValue( statsNamedContainer ) );
42+
Assert.assertEquals( 1, invocationCounterNullProducer.get() );
43+
assertNull( getCacheWithNullValue( statsNamedContainer ) );
44+
Assert.assertEquals( 1, invocationCounterNullProducer.get() );
45+
}
46+
47+
@Test
48+
public void abletoStoreActualValues() {
49+
final StatsNamedContainer statsNamedContainer = new StatsNamedContainer<Integer>();
50+
Assert.assertEquals( 0, invocationCounterValueProducer.get() );
51+
Assert.assertEquals( 5, getCacheWithActualValue( statsNamedContainer ) );
52+
Assert.assertEquals( 1, invocationCounterValueProducer.get() );
53+
Assert.assertEquals( 5, getCacheWithActualValue( statsNamedContainer ) );
54+
Assert.assertEquals( 1, invocationCounterValueProducer.get() );
55+
}
56+
57+
private Object getCacheWithActualValue(StatsNamedContainer statsNamedContainer) {
58+
return statsNamedContainer.getOrCompute(
59+
"key",
60+
StatsNamedContainerNullComputedValueTest::produceValue
61+
);
62+
}
63+
64+
private Object getCacheWithNullValue(StatsNamedContainer statsNamedContainer) {
65+
return statsNamedContainer.getOrCompute(
66+
"key",
67+
StatsNamedContainerNullComputedValueTest::produceNull
68+
);
69+
}
70+
71+
private static Integer produceValue(Object o) {
72+
invocationCounterValueProducer.getAndIncrement();
73+
return Integer.valueOf( 5 );
74+
}
75+
76+
private static Integer produceNull(Object v) {
77+
invocationCounterNullProducer.getAndIncrement();
78+
return null;
79+
}
80+
81+
}

0 commit comments

Comments
 (0)