summaryrefslogtreecommitdiffstats
path: root/cps-ri/src
diff options
context:
space:
mode:
authordanielhanrahan <daniel.hanrahan@est.tech>2023-02-15 19:00:37 +0000
committerdanielhanrahan <daniel.hanrahan@est.tech>2023-02-16 12:05:02 +0000
commitfbb79a0a112da3b05989fdc3a8e88c5865f3cc9a (patch)
treec67557b80e46c8133fc70c254cf0f84e81fcbe11 /cps-ri/src
parente28b62148676d189bdd11b78d8d78419d548e358 (diff)
Improve batch delete schemasets performance
- Bulk delete anchors and datanodes associated with schemasets. Improves de-registration performance by approx 10% Issue-ID: CPS-1423 Signed-off-by: danielhanrahan <daniel.hanrahan@est.tech> Change-Id: Ie38e8b4c64356bf5935d8c7a5d3f5bfa73fb1714
Diffstat (limited to 'cps-ri/src')
-rwxr-xr-xcps-ri/src/main/java/org/onap/cps/spi/impl/CpsAdminPersistenceServiceImpl.java16
-rw-r--r--cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java9
-rwxr-xr-xcps-ri/src/main/java/org/onap/cps/spi/repository/AnchorRepository.java11
-rw-r--r--cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsAdminPersistenceServiceSpec.groovy27
-rwxr-xr-xcps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceIntegrationSpec.groovy18
-rw-r--r--cps-ri/src/test/groovy/org/onap/cps/spi/performance/CpsDataPersistenceServiceDeletePerfTest.groovy16
-rw-r--r--cps-ri/src/test/resources/data/anchor.sql5
7 files changed, 90 insertions, 12 deletions
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsAdminPersistenceServiceImpl.java b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsAdminPersistenceServiceImpl.java
index 2cebfc72c0..162b268d87 100755
--- a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsAdminPersistenceServiceImpl.java
+++ b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsAdminPersistenceServiceImpl.java
@@ -1,6 +1,6 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2020-2022 Nordix Foundation.
+ * Copyright (C) 2020-2023 Nordix Foundation.
* Modifications Copyright (C) 2020-2022 Bell Canada.
* Modifications Copyright (C) 2021 Pantheon.tech
* Modifications Copyright (C) 2022 TechMahindra Ltd.
@@ -131,6 +131,13 @@ public class CpsAdminPersistenceServiceImpl implements CpsAdminPersistenceServic
}
@Override
+ public Collection<Anchor> getAnchors(final String dataspaceName, final Collection<String> schemaSetNames) {
+ final DataspaceEntity dataspaceEntity = dataspaceRepository.getByName(dataspaceName);
+ return anchorRepository.findAllByDataspaceAndSchemaSetNameIn(dataspaceEntity, schemaSetNames)
+ .stream().map(CpsAdminPersistenceServiceImpl::toAnchor).collect(Collectors.toSet());
+ }
+
+ @Override
public Collection<Anchor> queryAnchors(final String dataspaceName, final Collection<String> inputModuleNames) {
try {
validateDataspaceAndModuleNames(dataspaceName, inputModuleNames);
@@ -157,6 +164,13 @@ public class CpsAdminPersistenceServiceImpl implements CpsAdminPersistenceServic
anchorRepository.delete(anchorEntity);
}
+ @Transactional
+ @Override
+ public void deleteAnchors(final String dataspaceName, final Collection<String> anchorNames) {
+ final var dataspaceEntity = dataspaceRepository.getByName(dataspaceName);
+ anchorRepository.deleteAllByDataspaceAndNameIn(dataspaceEntity, anchorNames);
+ }
+
private AnchorEntity getAnchorEntity(final String dataspaceName, final String anchorName) {
final var dataspaceEntity = dataspaceRepository.getByName(dataspaceName);
return anchorRepository.getByDataspaceAndName(dataspaceEntity, anchorName);
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java
index 5b310efd5d..a8e0025088 100644
--- a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java
+++ b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java
@@ -607,6 +607,15 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
@Override
@Transactional
+ public void deleteDataNodes(final String dataspaceName, final Collection<String> anchorNames) {
+ final DataspaceEntity dataspaceEntity = dataspaceRepository.getByName(dataspaceName);
+ final Collection<AnchorEntity> anchorEntities =
+ anchorRepository.findAllByDataspaceAndNameIn(dataspaceEntity, anchorNames);
+ fragmentRepository.deleteByAnchorIn(anchorEntities);
+ }
+
+ @Override
+ @Transactional
public void deleteDataNodes(final String dataspaceName, final String anchorName,
final Collection<String> xpathsToDelete) {
final DataspaceEntity dataspaceEntity = dataspaceRepository.getByName(dataspaceName);
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/AnchorRepository.java b/cps-ri/src/main/java/org/onap/cps/spi/repository/AnchorRepository.java
index 3dbd578c73..46b0fec1c2 100755
--- a/cps-ri/src/main/java/org/onap/cps/spi/repository/AnchorRepository.java
+++ b/cps-ri/src/main/java/org/onap/cps/spi/repository/AnchorRepository.java
@@ -47,6 +47,12 @@ public interface AnchorRepository extends JpaRepository<AnchorEntity, Integer> {
Collection<AnchorEntity> findAllBySchemaSet(@NotNull SchemaSetEntity schemaSetEntity);
+ Collection<AnchorEntity> findAllByDataspaceAndNameIn(@NotNull DataspaceEntity dataspaceEntity,
+ @NotNull Collection<String> anchorNames);
+
+ Collection<AnchorEntity> findAllByDataspaceAndSchemaSetNameIn(@NotNull DataspaceEntity dataspaceEntity,
+ @NotNull Collection<String> schemaSetNames);
+
Integer countByDataspace(@NotNull DataspaceEntity dataspaceEntity);
@Query(value = "SELECT anchor.* FROM yang_resource\n"
@@ -58,4 +64,7 @@ public interface AnchorRepository extends JpaRepository<AnchorEntity, Integer> {
+ "HAVING COUNT(DISTINCT module_name) = :sizeOfModuleNames", nativeQuery = true)
Collection<AnchorEntity> getAnchorsByDataspaceIdAndModuleNames(@Param("dataspaceId") int dataspaceId,
@Param("moduleNames") Collection<String> moduleNames, @Param("sizeOfModuleNames") int sizeOfModuleNames);
-} \ No newline at end of file
+
+ void deleteAllByDataspaceAndNameIn(@NotNull DataspaceEntity dataspaceEntity,
+ @NotNull Collection<String> anchorNames);
+}
diff --git a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsAdminPersistenceServiceSpec.groovy b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsAdminPersistenceServiceSpec.groovy
index 99d44aac89..28d3bcfa4c 100644
--- a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsAdminPersistenceServiceSpec.groovy
+++ b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsAdminPersistenceServiceSpec.groovy
@@ -1,6 +1,6 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2021-2022 Nordix Foundation
+ * Copyright (C) 2021-2023 Nordix Foundation
* Modifications Copyright (C) 2021 Pantheon.tech
* Modifications Copyright (C) 2022 Bell Canada
* Modifications Copyright (C) 2022 TechMahindra Ltd.
@@ -142,7 +142,8 @@ class CpsAdminPersistenceServiceSpec extends CpsPersistenceSpecBase {
where: 'the following data is used'
dataspaceName || expectedAnchors
DATASPACE_NAME || [Anchor.builder().name(ANCHOR_NAME1).schemaSetName(SCHEMA_SET_NAME1).dataspaceName(DATASPACE_NAME).build(),
- Anchor.builder().name(ANCHOR_NAME2).schemaSetName(SCHEMA_SET_NAME2).dataspaceName(DATASPACE_NAME).build()]
+ Anchor.builder().name(ANCHOR_NAME2).schemaSetName(SCHEMA_SET_NAME2).dataspaceName(DATASPACE_NAME).build(),
+ Anchor.builder().name(ANCHOR_NAME3).schemaSetName(SCHEMA_SET_NAME2).dataspaceName(DATASPACE_NAME).build()]
DATASPACE_WITH_NO_DATA || []
}
@@ -179,6 +180,17 @@ class CpsAdminPersistenceServiceSpec extends CpsPersistenceSpecBase {
}
@Sql([CLEAR_DATA, SET_DATA])
+ def 'Get all anchors associated with multiple schemasets in a dataspace.'() {
+ when: 'anchors are retrieved by dataspace and schema-sets'
+ def anchors = objectUnderTest.getAnchors('DATASPACE-001', ['SCHEMA-SET-001', 'SCHEMA-SET-002'])
+ then: ' the response contains expected anchors'
+ anchors == Set.of(
+ new Anchor('ANCHOR-001', 'DATASPACE-001', 'SCHEMA-SET-001'),
+ new Anchor('ANCHOR-002', 'DATASPACE-001', 'SCHEMA-SET-002'),
+ new Anchor('ANCHOR-003', 'DATASPACE-001', 'SCHEMA-SET-002'))
+ }
+
+ @Sql([CLEAR_DATA, SET_DATA])
def 'Delete anchor'() {
when: 'delete anchor action is invoked'
objectUnderTest.deleteAnchor(DATASPACE_NAME, ANCHOR_NAME2)
@@ -198,6 +210,15 @@ class CpsAdminPersistenceServiceSpec extends CpsPersistenceSpecBase {
'anchor does not exists' | DATASPACE_NAME | 'unknown' || AnchorNotFoundException
}
+ @Sql([CLEAR_DATA, SET_DATA])
+ def 'Delete multiple anchors'() {
+ when: 'delete anchors action is invoked'
+ objectUnderTest.deleteAnchors(DATASPACE_NAME, ['ANCHOR-002', 'ANCHOR-003'])
+ then: 'anchors are deleted'
+ anchorRepository.findById(3002).isEmpty()
+ anchorRepository.findById(3003).isEmpty()
+ }
+
@Sql([CLEAR_DATA, SAMPLE_DATA_FOR_ANCHORS_WITH_MODULES])
def 'Query anchors that have #scenario.'() {
when: 'all anchor are retrieved for the given dataspace name and module names'
@@ -236,7 +257,7 @@ class CpsAdminPersistenceServiceSpec extends CpsPersistenceSpecBase {
where: 'the following data is used'
scenario | dataspaceName || expectedException | expectedMessageDetails
'dataspace name does not exist' | 'unknown' || DataspaceNotFoundException | 'unknown does not exist'
- 'dataspace contains an anchor' | 'DATASPACE-001' || DataspaceInUseException | 'contains 2 anchor(s)'
+ 'dataspace contains an anchor' | 'DATASPACE-001' || DataspaceInUseException | 'contains 3 anchor(s)'
'dataspace contains schemasets' | 'DATASPACE-003' || DataspaceInUseException | 'contains 1 schemaset(s)'
}
}
diff --git a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceIntegrationSpec.groovy b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceIntegrationSpec.groovy
index e4c552978d..91024082af 100755
--- a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceIntegrationSpec.groovy
+++ b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceIntegrationSpec.groovy
@@ -54,8 +54,6 @@ class CpsDataPersistenceServiceIntegrationSpec extends CpsPersistenceSpecBase {
static DataNodeBuilder dataNodeBuilder = new DataNodeBuilder()
static final String SET_DATA = '/data/fragment.sql'
- static int DATASPACE_1001_ID = 1001L
- static int ANCHOR_3003_ID = 3003L
static long ID_DATA_NODE_WITH_DESCENDANTS = 4001
static String XPATH_DATA_NODE_WITH_DESCENDANTS = '/parent-1'
static String XPATH_DATA_NODE_WITH_LEAVES = '/parent-207'
@@ -667,11 +665,23 @@ class CpsDataPersistenceServiceIntegrationSpec extends CpsPersistenceSpecBase {
@Sql([CLEAR_DATA, SET_DATA])
def 'Delete data node for an anchor.'() {
given: 'a data-node exists for an anchor'
- assert fragmentsExistInDB(DATASPACE_1001_ID, ANCHOR_3003_ID)
+ assert fragmentsExistInDB(1001, 3003)
when: 'data nodes are deleted '
objectUnderTest.deleteDataNodes(DATASPACE_NAME, ANCHOR_NAME3)
then: 'all data-nodes are deleted successfully'
- assert !fragmentsExistInDB(DATASPACE_1001_ID, ANCHOR_3003_ID)
+ assert !fragmentsExistInDB(1001, 3003)
+ }
+
+ @Sql([CLEAR_DATA, SET_DATA])
+ def 'Delete data node for multiple anchors.'() {
+ given: 'a data-node exists for an anchor'
+ assert fragmentsExistInDB(1001, 3001)
+ assert fragmentsExistInDB(1001, 3003)
+ when: 'data nodes are deleted '
+ objectUnderTest.deleteDataNodes(DATASPACE_NAME, ['ANCHOR-001', 'ANCHOR-003'])
+ then: 'all data-nodes are deleted successfully'
+ assert !fragmentsExistInDB(1001, 3001)
+ assert !fragmentsExistInDB(1001, 3003)
}
def fragmentsExistInDB(dataSpaceId, anchorId) {
diff --git a/cps-ri/src/test/groovy/org/onap/cps/spi/performance/CpsDataPersistenceServiceDeletePerfTest.groovy b/cps-ri/src/test/groovy/org/onap/cps/spi/performance/CpsDataPersistenceServiceDeletePerfTest.groovy
index 3b9338ce41..706b35ebb7 100644
--- a/cps-ri/src/test/groovy/org/onap/cps/spi/performance/CpsDataPersistenceServiceDeletePerfTest.groovy
+++ b/cps-ri/src/test/groovy/org/onap/cps/spi/performance/CpsDataPersistenceServiceDeletePerfTest.groovy
@@ -212,7 +212,7 @@ class CpsDataPersistenceServiceDeletePerfTest extends CpsPersistencePerfSpecBase
}
@Sql([CLEAR_DATA, PERF_TEST_DATA])
- def 'Delete data nodes for an anchor'() {212
+ def 'Delete data nodes for an anchor'() {
given: 'a node with a large number of descendants is created'
createLineage(objectUnderTest, 50, 50, false)
createLineage(objectUnderTest, 50, 50, true)
@@ -225,4 +225,18 @@ class CpsDataPersistenceServiceDeletePerfTest extends CpsPersistencePerfSpecBase
recordAndAssertPerformance('Delete data nodes for anchor', 300, deleteDurationInMillis)
}
+ @Sql([CLEAR_DATA, PERF_TEST_DATA])
+ def 'Delete data nodes for multiple anchors'() {
+ given: 'a node with a large number of descendants is created'
+ createLineage(objectUnderTest, 50, 50, false)
+ createLineage(objectUnderTest, 50, 50, true)
+ when: 'data nodes are deleted'
+ stopWatch.start()
+ objectUnderTest.deleteDataNodes(PERF_DATASPACE, [PERF_ANCHOR])
+ stopWatch.stop()
+ def deleteDurationInMillis = stopWatch.getTotalTimeMillis()
+ then: 'delete duration is under 300 milliseconds'
+ recordAndAssertPerformance('Delete data nodes for anchor', 300, deleteDurationInMillis)
+ }
+
}
diff --git a/cps-ri/src/test/resources/data/anchor.sql b/cps-ri/src/test/resources/data/anchor.sql
index 40fc44c0ae..2ab7966e18 100644
--- a/cps-ri/src/test/resources/data/anchor.sql
+++ b/cps-ri/src/test/resources/data/anchor.sql
@@ -1,7 +1,7 @@
/*
============LICENSE_START=======================================================
Copyright (C) 2020 Pantheon.tech
- Modifications Copyright (C) 2020 Nordix Foundation.
+ Modifications Copyright (C) 2020-2023 Nordix Foundation.
Modifications Copyright (C) 2021-2022 Bell Canada.
================================================================================
Licensed under the Apache License, Version 2.0 (the "License");
@@ -32,7 +32,8 @@ INSERT INTO SCHEMA_SET (ID, NAME, DATASPACE_ID) VALUES
INSERT INTO ANCHOR (ID, NAME, DATASPACE_ID, SCHEMA_SET_ID) VALUES
(3001, 'ANCHOR-001', 1001, 2001),
- (3002, 'ANCHOR-002', 1001, 2002);
+ (3002, 'ANCHOR-002', 1001, 2002),
+ (3003, 'ANCHOR-003', 1001, 2002);
INSERT INTO FRAGMENT (ID, DATASPACE_ID, ANCHOR_ID, PARENT_ID, XPATH, ATTRIBUTES) VALUES
(4001, 1001, 3001, null, '/xpath', '{}');