summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormpriyank <priyank.maheshwari@est.tech>2022-08-26 13:26:01 +0100
committermpriyank <priyank.maheshwari@est.tech>2022-08-29 15:15:54 +0100
commit91d66108379d7cd397aedc30da4801d20643ee68 (patch)
tree63c73329d3478b641b479d56fb31e8d2e10c31be
parentbf1fdbdeed0ba6f0e8420d15ab33d6c88a5ee4d5 (diff)
Performance Improvement:save cmhandles capability
- add saveCmHandleBatch in InventoryPersistence - add saveListElementsBatch in CpsDataService - have addListElementsBatch in CpsDataPersistenceService - Test scenarios for the same Issue-ID: CPS-1229 Issue-ID: CPS-1126 Change-Id: I0a1401818da5a4e523d7d0751cac6a526d1611b2 Signed-off-by: mpriyank <priyank.maheshwari@est.tech>
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/InventoryPersistence.java15
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/InventoryPersistenceSpec.groovy16
-rw-r--r--cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java10
-rwxr-xr-xcps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceIntegrationSpec.groovy4
-rw-r--r--cps-service/src/main/java/org/onap/cps/api/CpsDataService.java13
-rwxr-xr-xcps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java18
-rw-r--r--cps-service/src/main/java/org/onap/cps/spi/CpsDataPersistenceService.java11
-rw-r--r--cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy21
8 files changed, 106 insertions, 2 deletions
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/InventoryPersistence.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/InventoryPersistence.java
index c059ece0d3..7a7ef66668 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/InventoryPersistence.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/InventoryPersistence.java
@@ -27,8 +27,10 @@ import static org.onap.cps.spi.CascadeDeleteAllowed.CASCADE_DELETE_ALLOWED;
import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS;
import java.time.OffsetDateTime;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -157,6 +159,19 @@ public class InventoryPersistence {
}
/**
+ * Method to save batch of cm handles.
+ *
+ * @param yangModelCmHandles cm handle represented as Yang Models
+ */
+ public void saveCmHandleBatch(final Collection<YangModelCmHandle> yangModelCmHandles) {
+ final List<String> cmHandlesJsonData = new ArrayList<>();
+ yangModelCmHandles.forEach(yangModelCmHandle -> cmHandlesJsonData.add(
+ String.format("{\"cm-handles\":[%s]}", jsonObjectMapper.asJsonString(yangModelCmHandle))));
+ cpsDataService.saveListElementsBatch(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
+ NCMP_DMI_REGISTRY_PARENT, cmHandlesJsonData, NO_TIMESTAMP);
+ }
+
+ /**
* Method to delete a list or a list element.
*
* @param listElementXpath list element xPath
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/InventoryPersistenceSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/InventoryPersistenceSpec.groovy
index 7ffec1ab09..76f10de831 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/InventoryPersistenceSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/InventoryPersistenceSpec.groovy
@@ -202,6 +202,22 @@ class InventoryPersistenceSpec extends Specification {
}
}
+ def 'Save Multiple Cmhandles'() {
+ given: 'cm handles represented as Yang Model'
+ def yangModelCmHandle1 = new YangModelCmHandle(id: 'cmhandle1')
+ def yangModelCmHandle2 = new YangModelCmHandle(id: 'cmhandle2')
+ when: 'the cm handles are saved'
+ objectUnderTest.saveCmHandleBatch([yangModelCmHandle1, yangModelCmHandle2])
+ then: 'CPS Data Service persists both cm handles as a batch'
+ 1 * mockCpsDataService.saveListElementsBatch('NCMP-Admin','ncmp-dmi-registry','/dmi-registry',_,null) >> {
+ args -> {
+ def jsonDataList = (args[3] as List)
+ (jsonDataList[0] as String).contains('cmhandle1')
+ (jsonDataList[0] as String).contains('cmhandle2')
+ }
+ }
+ }
+
def 'Delete list or list elements'() {
when: 'the method to delete list or list elements is called'
objectUnderTest.deleteListOrListElement('sample xPath')
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 c4a2c2fe98..61e1d5b569 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
@@ -101,6 +101,16 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
addChildDataNodes(dataspaceName, anchorName, parentNodeXpath, newListElements);
}
+ @Override
+ @Transactional
+ public void addListElementsBatch(final String dataspaceName, final String anchorName, final String parentNodeXpath,
+ final Collection<Collection<DataNode>> newListsElements) {
+
+ newListsElements.forEach(
+ newListElement -> addListElements(dataspaceName, anchorName, parentNodeXpath, newListElement));
+
+ }
+
private void addChildDataNodes(final String dataspaceName, final String anchorName, final String parentNodeXpath,
final Collection<DataNode> newChildren) {
final FragmentEntity parentFragmentEntity = getFragmentByXpath(dataspaceName, anchorName, parentNodeXpath);
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 fee489d18b..acc243b5b4 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
@@ -157,7 +157,7 @@ class CpsDataPersistenceServiceIntegrationSpec extends CpsPersistenceSpecBase {
}
@Sql([CLEAR_DATA, SET_DATA])
- def 'Add multiple new list elements including an element with a child datanode.'() {
+ def 'Add collection of multiple new list elements including an element with a child datanode.'() {
given: 'two new child list elements for an existing parent'
def listElementXpaths = ['/parent-201/child-204[@key="NEW1"]', '/parent-201/child-204[@key="NEW2"]']
def listElements = toDataNodes(listElementXpaths)
@@ -165,7 +165,7 @@ class CpsDataPersistenceServiceIntegrationSpec extends CpsPersistenceSpecBase {
def grandChild = buildDataNode('/parent-201/child-204[@key="NEW1"]/grand-child-204[@key2="NEW1-CHILD"]', [leave:'value'], [])
listElements[0].childDataNodes = [grandChild]
when: 'the new data node (list elements) are added to an existing parent node'
- objectUnderTest.addListElements(DATASPACE_NAME, ANCHOR_NAME3, '/parent-201', listElements)
+ objectUnderTest.addListElementsBatch(DATASPACE_NAME, ANCHOR_NAME3, '/parent-201', [listElements])
then: 'new entries are successfully persisted, parent node now contains 5 children (2 new + 3 existing before)'
def parentFragment = fragmentRepository.getById(LIST_DATA_NODE_PARENT201_FRAGMENT_ID)
def allChildXpaths = parentFragment.childFragments.collect { it.xpath }
diff --git a/cps-service/src/main/java/org/onap/cps/api/CpsDataService.java b/cps-service/src/main/java/org/onap/cps/api/CpsDataService.java
index decf67d24e..b2e8c5ba42 100644
--- a/cps-service/src/main/java/org/onap/cps/api/CpsDataService.java
+++ b/cps-service/src/main/java/org/onap/cps/api/CpsDataService.java
@@ -69,6 +69,19 @@ public interface CpsDataService {
OffsetDateTime observedTimestamp);
/**
+ * Persists child data fragment representing one or more list elements under existing data node for the
+ * given anchor and dataspace.
+ *
+ * @param dataspaceName dataspace name
+ * @param anchorName anchor name
+ * @param parentNodeXpath parent node xpath
+ * @param jsonDataList collection of json data representing list element(s)
+ * @param observedTimestamp observedTimestamp
+ */
+ void saveListElementsBatch(String dataspaceName, String anchorName, String parentNodeXpath,
+ Collection<String> jsonDataList, OffsetDateTime observedTimestamp);
+
+ /**
* Retrieves datanode by XPath for given dataspace and anchor.
*
* @param dataspaceName dataspace name
diff --git a/cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java b/cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java
index 092fd31fcf..6bf493556e 100755
--- a/cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java
+++ b/cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java
@@ -92,6 +92,17 @@ public class CpsDataServiceImpl implements CpsDataService {
}
@Override
+ public void saveListElementsBatch(final String dataspaceName, final String anchorName, final String parentNodeXpath,
+ final Collection<String> jsonDataList, final OffsetDateTime observedTimestamp) {
+ CpsValidator.validateNameCharacters(dataspaceName, anchorName);
+ final Collection<Collection<DataNode>> listElementDataNodeCollections =
+ buildDataNodes(dataspaceName, anchorName, parentNodeXpath, jsonDataList);
+ cpsDataPersistenceService.addListElementsBatch(dataspaceName, anchorName, parentNodeXpath,
+ listElementDataNodeCollections);
+ processDataUpdatedEventAsync(dataspaceName, anchorName, parentNodeXpath, UPDATE, observedTimestamp);
+ }
+
+ @Override
public DataNode getDataNode(final String dataspaceName, final String anchorName, final String xpath,
final FetchDescendantsOption fetchDescendantsOption) {
CpsValidator.validateNameCharacters(dataspaceName, anchorName);
@@ -252,6 +263,13 @@ public class CpsDataServiceImpl implements CpsDataService {
}
+ private Collection<Collection<DataNode>> buildDataNodes(final String dataspaceName, final String anchorName,
+ final String parentNodeXpath, final Collection<String> jsonDataList) {
+ return jsonDataList.stream()
+ .map(jsonData -> buildDataNodes(dataspaceName, anchorName, parentNodeXpath, jsonData))
+ .collect(Collectors.toList());
+ }
+
private void processDataUpdatedEventAsync(final String dataspaceName, final String anchorName, final String xpath,
final Operation operation, final OffsetDateTime observedTimestamp) {
try {
diff --git a/cps-service/src/main/java/org/onap/cps/spi/CpsDataPersistenceService.java b/cps-service/src/main/java/org/onap/cps/spi/CpsDataPersistenceService.java
index 686f0f3fee..8b45ae78d9 100644
--- a/cps-service/src/main/java/org/onap/cps/spi/CpsDataPersistenceService.java
+++ b/cps-service/src/main/java/org/onap/cps/spi/CpsDataPersistenceService.java
@@ -66,6 +66,17 @@ public interface CpsDataPersistenceService {
Collection<DataNode> listElementsCollection);
/**
+ * Adds list child elements to a Fragment.
+ *
+ * @param dataspaceName dataspace name
+ * @param anchorName anchor name
+ * @param parentNodeXpath parent node xpath
+ * @param listElementsCollections collections of data nodes representing list elements
+ */
+ void addListElementsBatch(String dataspaceName, String anchorName, String parentNodeXpath,
+ Collection<Collection<DataNode>> listElementsCollections);
+
+ /**
* Retrieves datanode by XPath for given dataspace and anchor.
*
* @param dataspaceName dataspace name
diff --git a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy
index cb352bccec..ab960df6aa 100644
--- a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy
+++ b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy
@@ -37,6 +37,7 @@ import org.onap.cps.yang.YangTextSchemaSourceSetBuilder
import spock.lang.Specification
import java.time.OffsetDateTime
+import java.util.stream.Collectors
class CpsDataServiceImplSpec extends Specification {
def mockCpsDataPersistenceService = Mock(CpsDataPersistenceService)
@@ -135,6 +136,26 @@ class CpsDataServiceImplSpec extends Specification {
1 * mockNotificationService.processDataUpdatedEvent(dataspaceName, anchorName, '/test-tree', Operation.UPDATE, observedTimestamp)
}
+ def 'Saving collection of a batch with data fragment under existing node.'() {
+ given: 'schema set for given anchor and dataspace references test-tree model'
+ setupSchemaSetMocks('test-tree.yang')
+ when: 'save data method is invoked with list element json data'
+ def jsonData = '{"branch": [{"name": "A"}, {"name": "B"}]}'
+ objectUnderTest.saveListElementsBatch(dataspaceName, anchorName, '/test-tree', [jsonData], observedTimestamp)
+ then: 'the persistence service method is invoked with correct parameters'
+ 1 * mockCpsDataPersistenceService.addListElementsBatch(dataspaceName, anchorName, '/test-tree',_) >> {
+ args -> {
+ def listElementsCollection = args[3] as Collection<Collection<DataNode>>
+ assert listElementsCollection.size() == 1
+ def listOfXpaths = listElementsCollection.stream().flatMap(x -> x.stream()).map(it-> it.xpath).collect(Collectors.toList())
+ assert listOfXpaths.size() == 2
+ assert listOfXpaths.containsAll(['/test-tree/branch[@name=\'B\']','/test-tree/branch[@name=\'A\']'])
+ }
+ }
+ and: 'data updated event is sent to notification service'
+ 1 * mockNotificationService.processDataUpdatedEvent(dataspaceName, anchorName, '/test-tree', Operation.UPDATE, observedTimestamp)
+ }
+
def 'Saving empty list element data fragment.'() {
given: 'schema set for given anchor and dataspace references test-tree model'
setupSchemaSetMocks('test-tree.yang')