Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
667ecbb556
@ -0,0 +1,44 @@
|
|||||||
|
package com.baeldung.arrays;
|
||||||
|
|
||||||
|
import org.openjdk.jmh.annotations.*;
|
||||||
|
import org.openjdk.jmh.infra.Blackhole;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
public class ParallelPrefixBenchmark {
|
||||||
|
private static final int ARRAY_SIZE = 200_000_000;
|
||||||
|
|
||||||
|
@State(Scope.Benchmark)
|
||||||
|
public static class BigArray {
|
||||||
|
|
||||||
|
int[] data;
|
||||||
|
|
||||||
|
@Setup(Level.Iteration)
|
||||||
|
public void prepare() {
|
||||||
|
data = new int[ARRAY_SIZE];
|
||||||
|
for(int j = 0; j< ARRAY_SIZE; j++) {
|
||||||
|
data[j] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@TearDown(Level.Iteration)
|
||||||
|
public void destroy() {
|
||||||
|
data = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public void largeArrayLoopSum(BigArray bigArray, Blackhole blackhole) {
|
||||||
|
for (int i = 0; i < ARRAY_SIZE - 1; i++) {
|
||||||
|
bigArray.data[i + 1] += bigArray.data[i];
|
||||||
|
}
|
||||||
|
blackhole.consume(bigArray.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public void largeArrayParallelPrefixSum(BigArray bigArray, Blackhole blackhole) {
|
||||||
|
Arrays.parallelPrefix(bigArray.data, (left, right) -> left + right);
|
||||||
|
blackhole.consume(bigArray.data);
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,7 @@
|
|||||||
package com.baeldung.arrays;
|
package com.baeldung.arrays;
|
||||||
|
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.hamcrest.Matchers.is;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
@ -9,6 +11,7 @@ import org.junit.rules.ExpectedException;
|
|||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
public class ArraysUnitTest {
|
public class ArraysUnitTest {
|
||||||
@ -150,4 +153,52 @@ public class ArraysUnitTest {
|
|||||||
exception.expect(UnsupportedOperationException.class);
|
exception.expect(UnsupportedOperationException.class);
|
||||||
rets.add("the");
|
rets.add("the");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenIntArray_whenPrefixAdd_thenAllAccumulated() {
|
||||||
|
int[] arri = new int[] { 1, 2, 3, 4};
|
||||||
|
Arrays.parallelPrefix(arri, (left, right) -> left + right);
|
||||||
|
assertThat(arri, is(new int[] { 1, 3, 6, 10}));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenStringArray_whenPrefixConcat_thenAllMerged() {
|
||||||
|
String[] arrs = new String[] { "1", "2", "3" };
|
||||||
|
Arrays.parallelPrefix(arrs, (left, right) -> left + right);
|
||||||
|
assertThat(arrs, is(new String[] { "1", "12", "123" }));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenPrefixAddWithRange_thenRangeAdded() {
|
||||||
|
int[] arri = new int[] { 1, 2, 3, 4, 5 };
|
||||||
|
Arrays.parallelPrefix(arri, 1, 4, (left, right) -> left + right);
|
||||||
|
assertThat(arri, is(new int[] { 1, 2, 5, 9, 5 }));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenPrefixNonAssociative_thenError() {
|
||||||
|
boolean consistent = true;
|
||||||
|
Random r = new Random();
|
||||||
|
for (int k = 0; k < 100_000; k++) {
|
||||||
|
int[] arrA = r.ints(100, 1, 5).toArray();
|
||||||
|
int[] arrB = Arrays.copyOf(arrA, arrA.length);
|
||||||
|
|
||||||
|
Arrays.parallelPrefix(arrA, this::nonassociativeFunc);
|
||||||
|
|
||||||
|
for (int i = 1; i < arrB.length; i++) {
|
||||||
|
arrB[i] = nonassociativeFunc(arrB[i - 1], arrB[i]);
|
||||||
|
}
|
||||||
|
consistent = Arrays.equals(arrA, arrB);
|
||||||
|
if(!consistent) break;
|
||||||
|
}
|
||||||
|
assertFalse(consistent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* non-associative int binary operator
|
||||||
|
*/
|
||||||
|
private int nonassociativeFunc(int left, int right) {
|
||||||
|
return left + right*left;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,57 +1,10 @@
|
|||||||
package com.baeldung.cachetest.config;
|
package com.baeldung.cachetest.config;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.time.Duration;
|
|
||||||
|
|
||||||
import javax.cache.CacheManager;
|
|
||||||
|
|
||||||
import org.ehcache.config.CacheConfiguration;
|
|
||||||
import org.ehcache.config.ResourcePools;
|
|
||||||
import org.ehcache.config.builders.CacheConfigurationBuilder;
|
|
||||||
import org.ehcache.config.builders.CacheEventListenerConfigurationBuilder;
|
|
||||||
import org.ehcache.config.builders.ExpiryPolicyBuilder;
|
|
||||||
import org.ehcache.config.builders.ResourcePoolsBuilder;
|
|
||||||
import org.ehcache.config.units.EntryUnit;
|
|
||||||
import org.ehcache.config.units.MemoryUnit;
|
|
||||||
import org.ehcache.event.EventType;
|
|
||||||
import org.ehcache.jsr107.Eh107Configuration;
|
|
||||||
import org.springframework.boot.autoconfigure.cache.JCacheManagerCustomizer;
|
|
||||||
import org.springframework.cache.annotation.EnableCaching;
|
import org.springframework.cache.annotation.EnableCaching;
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableCaching
|
@EnableCaching
|
||||||
public class CacheConfig {
|
public class CacheConfig {
|
||||||
|
|
||||||
private static final int ON_HEAP_CACHE_SIZE_ENTRIES = 2;
|
|
||||||
private static final int OFF_HEAP_CACHE_SIZE_MB = 10;
|
|
||||||
private static final int CACHE_EXPIRY_SECONDS = 30;
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public JCacheManagerCustomizer jcacheManagerCustomizer() {
|
|
||||||
return new JCacheManagerCustomizer() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void customize(CacheManager cacheManager) {
|
|
||||||
ResourcePools resourcePools = ResourcePoolsBuilder.newResourcePoolsBuilder()
|
|
||||||
.heap(ON_HEAP_CACHE_SIZE_ENTRIES, EntryUnit.ENTRIES)
|
|
||||||
.offheap(OFF_HEAP_CACHE_SIZE_MB, MemoryUnit.MB).build();
|
|
||||||
|
|
||||||
CacheEventListenerConfigurationBuilder eventLoggerConfig = CacheEventListenerConfigurationBuilder
|
|
||||||
.newEventListenerConfiguration(new CacheEventLogger(), EventType.CREATED, EventType.EXPIRED)
|
|
||||||
.unordered().asynchronous();
|
|
||||||
|
|
||||||
CacheConfiguration<?, ?> cacheConfiguration = CacheConfigurationBuilder
|
|
||||||
.newCacheConfigurationBuilder(Long.class, BigDecimal.class, resourcePools)
|
|
||||||
.withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofSeconds(CACHE_EXPIRY_SECONDS)))
|
|
||||||
.add(eventLoggerConfig).build();
|
|
||||||
|
|
||||||
cacheManager.createCache("squareCache",
|
|
||||||
Eh107Configuration.fromEhcacheCacheConfiguration(cacheConfiguration));
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -7,12 +7,11 @@ import org.slf4j.LoggerFactory;
|
|||||||
|
|
||||||
public class CacheEventLogger implements CacheEventListener<Object, Object> {
|
public class CacheEventLogger implements CacheEventListener<Object, Object> {
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(CacheEventLogger.class);
|
private static final Logger log = LoggerFactory.getLogger(CacheEventLogger.class);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEvent(CacheEvent<? extends Object, ? extends Object> cacheEvent) {
|
public void onEvent(CacheEvent<? extends Object, ? extends Object> cacheEvent) {
|
||||||
log.info("Cache event {} for item with key {}. Old value = {}, New value = {}", cacheEvent.getType(),
|
log.info("Cache event {} for item with key {}. Old value = {}, New value = {}", cacheEvent.getType(), cacheEvent.getKey(), cacheEvent.getOldValue(), cacheEvent.getNewValue());
|
||||||
cacheEvent.getKey(), cacheEvent.getOldValue(), cacheEvent.getNewValue());
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -15,15 +15,15 @@ import com.baeldung.cachetest.service.NumberService;
|
|||||||
@RequestMapping(path = "/number", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
@RequestMapping(path = "/number", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
||||||
public class NumberController {
|
public class NumberController {
|
||||||
|
|
||||||
private final static Logger log = LoggerFactory.getLogger(NumberController.class);
|
private final static Logger log = LoggerFactory.getLogger(NumberController.class);
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private NumberService numberService;
|
private NumberService numberService;
|
||||||
|
|
||||||
@GetMapping(path = "/square/{number}")
|
@GetMapping(path = "/square/{number}")
|
||||||
public String getThing(@PathVariable Long number) {
|
public String getThing(@PathVariable Long number) {
|
||||||
log.info("call numberService to square {}", number);
|
log.info("call numberService to square {}", number);
|
||||||
return String.format("{\"square\": %s}", numberService.square(number));
|
return String.format("{\"square\": %s}", numberService.square(number));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -10,13 +10,14 @@ import org.springframework.stereotype.Service;
|
|||||||
@Service
|
@Service
|
||||||
public class NumberService {
|
public class NumberService {
|
||||||
|
|
||||||
private final static Logger log = LoggerFactory.getLogger(NumberService.class);
|
private final static Logger log = LoggerFactory.getLogger(NumberService.class);
|
||||||
|
|
||||||
@Cacheable(value = "squareCache", key = "#number", condition = "#number>10")
|
@Cacheable(value = "squareCache", key = "#number", condition = "#number>10")
|
||||||
public BigDecimal square(Long number) {
|
public BigDecimal square(Long number) {
|
||||||
BigDecimal square = BigDecimal.valueOf(number).multiply(BigDecimal.valueOf(number));
|
BigDecimal square = BigDecimal.valueOf(number)
|
||||||
log.info("square of {} is {}", number, square);
|
.multiply(BigDecimal.valueOf(number));
|
||||||
return square;
|
log.info("square of {} is {}", number, square);
|
||||||
}
|
return square;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
1
spring-ehcache/src/main/resources/application.properties
Normal file
1
spring-ehcache/src/main/resources/application.properties
Normal file
@ -0,0 +1 @@
|
|||||||
|
spring.cache.jcache.config=classpath:ehcache.xml
|
31
spring-ehcache/src/main/resources/ehcache.xml
Normal file
31
spring-ehcache/src/main/resources/ehcache.xml
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xmlns="http://www.ehcache.org/v3"
|
||||||
|
xmlns:jsr107="http://www.ehcache.org/v3/jsr107"
|
||||||
|
xsi:schemaLocation="
|
||||||
|
http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core-3.0.xsd
|
||||||
|
http://www.ehcache.org/v3/jsr107 http://www.ehcache.org/schema/ehcache-107-ext-3.0.xsd">
|
||||||
|
|
||||||
|
<cache alias="squareCache">
|
||||||
|
<key-type>java.lang.Long</key-type>
|
||||||
|
<value-type>java.math.BigDecimal</value-type>
|
||||||
|
<expiry>
|
||||||
|
<ttl unit="seconds">30</ttl>
|
||||||
|
</expiry>
|
||||||
|
|
||||||
|
<listeners>
|
||||||
|
<listener>
|
||||||
|
<class>com.baeldung.cachetest.config.CacheEventLogger</class>
|
||||||
|
<event-firing-mode>ASYNCHRONOUS</event-firing-mode>
|
||||||
|
<event-ordering-mode>UNORDERED</event-ordering-mode>
|
||||||
|
<events-to-fire-on>CREATED</events-to-fire-on>
|
||||||
|
<events-to-fire-on>EXPIRED</events-to-fire-on>
|
||||||
|
</listener>
|
||||||
|
</listeners>
|
||||||
|
|
||||||
|
<resources>
|
||||||
|
<heap unit="entries">2</heap>
|
||||||
|
<offheap unit="MB">10</offheap>
|
||||||
|
</resources>
|
||||||
|
</cache>
|
||||||
|
|
||||||
|
</config>
|
Loading…
x
Reference in New Issue
Block a user