-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Optimize result deletion by defining explicit query
- Loading branch information
Hugo Marcellin
committed
Nov 29, 2023
1 parent
e6a950c
commit 0f8b1e0
Showing
6 changed files
with
226 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
103 changes: 103 additions & 0 deletions
103
...uite/sensitivityanalysis/server/repositories/SensitivityAnalysisResultRepositoryTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
/** | ||
* Copyright (c) 2023, RTE (http://www.rte-france.com) | ||
* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||
*/ | ||
package org.gridsuite.sensitivityanalysis.server.repositories; | ||
|
||
import com.powsybl.contingency.ContingencyContext; | ||
import com.powsybl.contingency.ContingencyContextType; | ||
import com.powsybl.sensitivity.*; | ||
import com.vladmihalcea.sql.SQLStatementCountValidator; | ||
import org.junit.Before; | ||
import org.junit.Test; | ||
import org.junit.runner.RunWith; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.boot.test.context.SpringBootTest; | ||
import org.springframework.test.context.junit4.SpringRunner; | ||
|
||
import java.util.*; | ||
import java.util.stream.Collectors; | ||
import java.util.stream.Stream; | ||
|
||
import static org.gridsuite.sensitivityanalysis.server.util.TestUtils.assertRequestsCount; | ||
|
||
/** | ||
* @author Hugo Marcellin <hugo.marcelin at rte-france.com> | ||
*/ | ||
@RunWith(SpringRunner.class) | ||
@SpringBootTest | ||
public class SensitivityAnalysisResultRepositoryTest { | ||
|
||
private static final SensitivityFunctionType MW_FUNC_TYPE = SensitivityFunctionType.BRANCH_ACTIVE_POWER_1; | ||
private static final SensitivityVariableType MW_VAR_TYPE = SensitivityVariableType.INJECTION_ACTIVE_POWER; | ||
private static final UUID RESULT_UUID = UUID.fromString("0c8de370-3e6c-4d72-b292-d355a97e0d5d"); | ||
|
||
@Autowired | ||
private SensitivityAnalysisResultRepository sensitivityAnalysisResultRepository; | ||
|
||
@Before | ||
public void setUp() { | ||
sensitivityAnalysisResultRepository.deleteAll(); | ||
SQLStatementCountValidator.reset(); | ||
} | ||
|
||
private static List<SensitivityFactor> makeMWFactors(String funcId, String varId, List<String> mayContingencies) { | ||
List<SensitivityFactor> aleaFactors; | ||
if (mayContingencies == null) { | ||
aleaFactors = List.of(new SensitivityFactor(MW_FUNC_TYPE, funcId, MW_VAR_TYPE, varId, false, ContingencyContext.all())); | ||
} else { | ||
aleaFactors = mayContingencies.stream().map(aleaId -> | ||
new SensitivityFactor(MW_FUNC_TYPE, funcId, MW_VAR_TYPE, varId, false, | ||
ContingencyContext.create(aleaId, ContingencyContextType.SPECIFIC))) | ||
.collect(Collectors.toList()); | ||
aleaFactors.add(0, new SensitivityFactor(MW_FUNC_TYPE, funcId, MW_VAR_TYPE, varId, false, ContingencyContext.none())); | ||
} | ||
return aleaFactors; | ||
} | ||
|
||
@Test | ||
public void deleteResultTest() { | ||
List<String> aleaIds = List.of("a1", "a2", "a3"); | ||
final List<SensitivityAnalysisResult.SensitivityContingencyStatus> contingenciesStatuses = aleaIds.stream() | ||
.map(aleaId -> new SensitivityAnalysisResult.SensitivityContingencyStatus(aleaId, SensitivityAnalysisResult.Status.SUCCESS)) | ||
.collect(Collectors.toList()); | ||
|
||
final List<SensitivityFactor> sensitivityFactors = Stream.of( | ||
makeMWFactors("l1", "GEN", null), // factor index 0 ; for all() | ||
makeMWFactors("l2", "GEN", List.of()), // factor index 1 ; for none() | ||
makeMWFactors("l3", "LOAD", aleaIds) // factor indices 2, 3, 4 & 5 | ||
).flatMap(Collection::stream).collect(Collectors.toList()); | ||
|
||
final List<SensitivityValue> sensitivityValues = new ArrayList<>(List.of( | ||
// l1 x GEN, before + a1, a2, a3 (implicit) | ||
new SensitivityValue(0, -1, 500.1, 2.9), | ||
new SensitivityValue(0, 0, 500.3, 2.7), | ||
new SensitivityValue(0, 1, 500.4, 2.6), | ||
new SensitivityValue(0, 2, 500.5, 2.5), | ||
// l2 x GEN, just before | ||
new SensitivityValue(1, -1, 500.2, 2.8), | ||
// l3 x LOAD, before + a1, a2, a3 (explicit) | ||
new SensitivityValue(2, -1, 500.9, 2.1), | ||
new SensitivityValue(3, 1, 500.6, 2.4), | ||
new SensitivityValue(4, 0, 500.7, 2.3), | ||
new SensitivityValue( 5, 2, 500.8, 2.2) | ||
)); | ||
Collections.shuffle(sensitivityValues); | ||
|
||
final SensitivityAnalysisResult result = new SensitivityAnalysisResult(sensitivityFactors, | ||
contingenciesStatuses, | ||
sensitivityValues); | ||
sensitivityAnalysisResultRepository.insert(RESULT_UUID, result, "OK"); | ||
SQLStatementCountValidator.reset(); | ||
|
||
sensitivityAnalysisResultRepository.delete(RESULT_UUID); | ||
|
||
// 3 deletes for one result : | ||
// - its global status | ||
// - its sensitivities | ||
// - the result itself | ||
assertRequestsCount(3, 0, 0, 3); | ||
} | ||
} |
79 changes: 79 additions & 0 deletions
79
.../java/org/gridsuite/sensitivityanalysis/server/util/DatasourceProxyBeanPostProcessor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
/** | ||
* Copyright (c) 2023, RTE (http://www.rte-france.com) | ||
* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||
*/ | ||
package org.gridsuite.sensitivityanalysis.server.util; | ||
|
||
import net.ttddyy.dsproxy.listener.ChainListener; | ||
import net.ttddyy.dsproxy.listener.DataSourceQueryCountListener; | ||
import net.ttddyy.dsproxy.listener.logging.SLF4JLogLevel; | ||
import net.ttddyy.dsproxy.support.ProxyDataSource; | ||
import net.ttddyy.dsproxy.support.ProxyDataSourceBuilder; | ||
import org.aopalliance.intercept.MethodInterceptor; | ||
import org.aopalliance.intercept.MethodInvocation; | ||
import org.springframework.aop.framework.ProxyFactory; | ||
import org.springframework.beans.factory.config.BeanPostProcessor; | ||
import org.springframework.stereotype.Component; | ||
import org.springframework.util.ReflectionUtils; | ||
|
||
import javax.sql.DataSource; | ||
import java.lang.reflect.Method; | ||
|
||
@Component | ||
/** | ||
* The author of db-utils describes its library in https://vladmihalcea.com/how-to-detect-the-n-plus-one-query-problem-during-testing/ | ||
* But the recommended method to select the datasource (using @bean public DataSource dataSource(DataSource originalDataSource) {...} ) | ||
* doesn't work when you use the spring default profile for tests | ||
* It crashes with this exception : java.lang.IllegalStateException: Failed to load ApplicationContext : org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'dataSource': Requested bean is currently in creation: Is there an unresolvable circular reference | ||
* Instead, the underlying datasource-proxy library author recommends to use a BeanPostProcessor: | ||
* https://github.com/ttddyy/datasource-proxy-examples/blob/master/springboot-autoconfig-example/src/main/java/net/ttddyy/dsproxy/example/DatasourceProxyBeanPostProcessor.java | ||
*/ | ||
public class DatasourceProxyBeanPostProcessor implements BeanPostProcessor { | ||
@Override | ||
public Object postProcessAfterInitialization(Object bean, String beanName) { | ||
if (bean instanceof DataSource && !(bean instanceof ProxyDataSource)) { | ||
// Instead of directly returning a less specific datasource bean | ||
// (e.g.: HikariDataSource -> DataSource), return a proxy object. | ||
// See following links for why: | ||
// https://stackoverflow.com/questions/44237787/how-to-use-user-defined-database-proxy-in-datajpatest | ||
// https://gitter.im/spring-projects/spring-boot?at=5983602d2723db8d5e70a904 | ||
// http://blog.arnoldgalovics.com/2017/06/26/configuring-a-datasource-proxy-in-spring-boot/ | ||
final ProxyFactory factory = new ProxyFactory(bean); | ||
factory.setProxyTargetClass(true); | ||
factory.addAdvice(new ProxyDataSourceInterceptor((DataSource) bean)); | ||
return factory.getProxy(); | ||
} | ||
return bean; | ||
} | ||
|
||
@Override | ||
public Object postProcessBeforeInitialization(Object bean, String beanName) { | ||
return bean; | ||
} | ||
|
||
private static class ProxyDataSourceInterceptor implements MethodInterceptor { | ||
private final DataSource dataSource; | ||
|
||
public ProxyDataSourceInterceptor(final DataSource dataSource) { | ||
ChainListener listener = new ChainListener(); | ||
listener.addListener(new DataSourceQueryCountListener()); | ||
this.dataSource = ProxyDataSourceBuilder.create(dataSource) | ||
.multiline() | ||
.listener(listener) | ||
.logQueryBySlf4j(SLF4JLogLevel.INFO) | ||
.build(); | ||
} | ||
|
||
@Override | ||
public Object invoke(final MethodInvocation invocation) throws Throwable { | ||
final Method proxyMethod = ReflectionUtils.findMethod(this.dataSource.getClass(), | ||
invocation.getMethod().getName()); | ||
if (proxyMethod != null) { | ||
return proxyMethod.invoke(this.dataSource, invocation.getArguments()); | ||
} | ||
return invocation.proceed(); | ||
} | ||
} | ||
} |
22 changes: 22 additions & 0 deletions
22
src/test/java/org/gridsuite/sensitivityanalysis/server/util/TestUtils.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
/** | ||
* Copyright (c) 2023, RTE (http://www.rte-france.com) | ||
* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||
*/ | ||
package org.gridsuite.sensitivityanalysis.server.util; | ||
|
||
|
||
import static com.vladmihalcea.sql.SQLStatementCountValidator.*; | ||
|
||
/** | ||
* @author Hugo Marcellin <hugo.marcelin at rte-france.com> | ||
*/ | ||
public final class TestUtils { | ||
public static void assertRequestsCount(long select, long insert, long update, long delete) { | ||
assertSelectCount(select); | ||
assertInsertCount(insert); | ||
assertUpdateCount(update); | ||
assertDeleteCount(delete); | ||
} | ||
} |