From c76392f0491e357b444b3458cc26649f7dc1e7fb Mon Sep 17 00:00:00 2001 From: DylanB95EST Date: Fri, 11 Feb 2022 12:46:27 +0000 Subject: Fragment handling decreasing performance for large number of cmHandles - allow fragmentEntity to set parent id (needed for optimization) - updated addListAlement and addChildDataNode to use new common optimized metghod to add to exsiting children - ensure methods are transactional - Refactored test around adding list elements to clearly define test checking the presence of grandchild element Issue-ID: CPS-886 Change-Id: Ic4381f0f7170ebd666d5bc8aa6ef2c4548d81766 Signed-off-by: DylanB95EST --- .../org/onap/cps/spi/entities/FragmentEntity.java | 3 ++ .../spi/impl/CpsDataPersistenceServiceImpl.java | 56 ++++++++-------------- ...CpsDataPersistenceServiceIntegrationSpec.groovy | 20 ++++---- 3 files changed, 34 insertions(+), 45 deletions(-) (limited to 'cps-ri') diff --git a/cps-ri/src/main/java/org/onap/cps/spi/entities/FragmentEntity.java b/cps-ri/src/main/java/org/onap/cps/spi/entities/FragmentEntity.java index 00d1d98df..2fdfa0528 100755 --- a/cps-ri/src/main/java/org/onap/cps/spi/entities/FragmentEntity.java +++ b/cps-ri/src/main/java/org/onap/cps/spi/entities/FragmentEntity.java @@ -70,6 +70,9 @@ public class FragmentEntity implements Serializable { @Column(columnDefinition = "text") private String xpath; + @Column(name = "parent_id") + private Long parentId; + @Type(type = "jsonb") @Column(columnDefinition = "jsonb") private String attributes; 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 ed414fc30..04804726c 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 @@ -73,41 +73,38 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService private final JsonObjectMapper jsonObjectMapper; - private static final String REG_EX_FOR_OPTIONAL_LIST_INDEX = "(\\[@[\\s\\S]+?]){0,1})"; private static final Pattern REG_EX_PATTERN_FOR_LIST_ELEMENT_KEY_PREDICATE = Pattern.compile("\\[(\\@([^\\/]{0,9999}))\\]$"); @Override - public void addChildDataNode(final String dataspaceName, final String anchorName, final String parentXpath, - final DataNode dataNode) { - final FragmentEntity parentFragment = getFragmentByXpath(dataspaceName, anchorName, parentXpath); - final FragmentEntity fragmentEntity = - toFragmentEntity(parentFragment.getDataspace(), parentFragment.getAnchor(), dataNode); - parentFragment.getChildFragments().add(fragmentEntity); - try { - fragmentRepository.save(parentFragment); - } catch (final DataIntegrityViolationException exception) { - throw AlreadyDefinedException.forDataNode(dataNode.getXpath(), anchorName, exception); - } + @Transactional + public void addChildDataNode(final String dataspaceName, final String anchorName, final String parentNodeXpath, + final DataNode newChildDataNode) { + addChildDataNodes(dataspaceName, anchorName, parentNodeXpath, Collections.singleton(newChildDataNode)); } @Override + @Transactional public void addListElements(final String dataspaceName, final String anchorName, final String parentNodeXpath, - final Collection dataNodes) { - final FragmentEntity parentFragment = getFragmentByXpath(dataspaceName, anchorName, parentNodeXpath); - final List newFragmentEntities = - dataNodes.stream().map( - dataNode -> toFragmentEntity(parentFragment.getDataspace(), parentFragment.getAnchor(), dataNode) - ).collect(Collectors.toUnmodifiableList()); - parentFragment.getChildFragments().addAll(newFragmentEntities); + final Collection newListElements) { + addChildDataNodes(dataspaceName, anchorName, parentNodeXpath, newListElements); + } + + private void addChildDataNodes(final String dataspaceName, final String anchorName, final String parentNodeXpath, + final Collection newChildren) { + final FragmentEntity parentFragmentEntity = getFragmentByXpath(dataspaceName, anchorName, parentNodeXpath); try { - fragmentRepository.save(parentFragment); - dataNodes.forEach( - dataNode -> getChildFragments(dataspaceName, anchorName, dataNode) - ); + for (final DataNode newChildAsDataNode : newChildren) { + final FragmentEntity newChildAsFragmentEntity = convertToFragmentWithAllDescendants( + parentFragmentEntity.getDataspace(), + parentFragmentEntity.getAnchor(), + newChildAsDataNode); + newChildAsFragmentEntity.setParentId(parentFragmentEntity.getId()); + fragmentRepository.save(newChildAsFragmentEntity); + } } catch (final DataIntegrityViolationException exception) { - final List conflictXpaths = dataNodes.stream() + final List conflictXpaths = newChildren.stream() .map(DataNode::getXpath) .collect(Collectors.toList()); throw AlreadyDefinedException.forDataNodes(conflictXpaths, anchorName, exception); @@ -150,17 +147,6 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService return parentFragment; } - private void getChildFragments(final String dataspaceName, final String anchorName, final DataNode dataNode) { - for (final DataNode childDataNode: dataNode.getChildDataNodes()) { - final FragmentEntity getChildsParentFragmentByXPath = - getFragmentByXpath(dataspaceName, anchorName, dataNode.getXpath()); - final FragmentEntity childFragmentEntity = toFragmentEntity(getChildsParentFragmentByXPath.getDataspace(), - getChildsParentFragmentByXPath.getAnchor(), childDataNode); - getChildsParentFragmentByXPath.getChildFragments().add(childFragmentEntity); - fragmentRepository.save(getChildsParentFragmentByXPath); - } - } - private FragmentEntity toFragmentEntity(final DataspaceEntity dataspaceEntity, final AnchorEntity anchorEntity, final DataNode dataNode) { return FragmentEntity.builder() 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 41e7a419a..2277377a5 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 @@ -155,25 +155,25 @@ class CpsDataPersistenceServiceIntegrationSpec extends CpsPersistenceSpecBase { } @Sql([CLEAR_DATA, SET_DATA]) - def 'Add multiple list elements including an element with a child datanode.'() { - given: 'two new data nodes for an existing list' + def 'Add 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) - and: 'a child node for one of the new data nodes' - def childDataNode = buildDataNode('/parent-201/child-204[@key="NEW1"]/grand-child-204[@key2="NEW1-CHILD"]', [leave:'value'], []) - listElements[0].childDataNodes = [childDataNode] - when: 'the data nodes (list elements) are added to existing parent node' + and: 'a (grand)child data node for one of the new list elements' + 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) - then: 'new entries successfully persisted, parent node now contains 5 children (2 new + 3 existing before)' + 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 } assert allChildXpaths.size() == 5 assert allChildXpaths.containsAll(listElementXpaths) - and: 'the child node of the new list entry is also present' + and: 'the (grand)child node of the new list entry is also present' def dataspaceEntity = dataspaceRepository.getByName(DATASPACE_NAME) def anchorEntity = anchorRepository.getByDataspaceAndName(dataspaceEntity, ANCHOR_NAME3) - def listElementChild = fragmentRepository.findByDataspaceAndAnchorAndXpath(dataspaceEntity, anchorEntity, childDataNode.xpath) - assert listElementChild.isPresent() + def grandChildFragmentEntity = fragmentRepository.findByDataspaceAndAnchorAndXpath(dataspaceEntity, anchorEntity, grandChild.xpath) + assert grandChildFragmentEntity.isPresent() } @Sql([CLEAR_DATA, SET_DATA]) -- cgit 1.2.3-korg