From 7b6ab50231f5ab39d1476531031437f81328115e Mon Sep 17 00:00:00 2001 From: mpriyank Date: Tue, 6 Sep 2022 18:29:34 +0100 Subject: Handle partial failure - Removing the transaction boundaries as it was getting rollbacked on partial failures - Handled adding the elements in batch and if it fails try them individually - Refactored code a bit and when there is partial failure we try one more time in sequence and even if there are failures we collect the failures Issue-ID: CPS-1232 Issue-ID: CPS-1126 Change-Id: I7824c9f37f80cbaeedd5dc06d598ca0e3a69c59b Signed-off-by: mpriyank --- .../spi/impl/CpsDataPersistenceServiceImpl.java | 67 +++++++++++++++------- 1 file changed, 46 insertions(+), 21 deletions(-) (limited to 'cps-ri/src/main') 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 61e1d5b56..e02fb7355 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 @@ -52,6 +52,7 @@ import org.onap.cps.spi.entities.FragmentEntity; import org.onap.cps.spi.entities.SchemaSetEntity; import org.onap.cps.spi.entities.YangResourceEntity; import org.onap.cps.spi.exceptions.AlreadyDefinedException; +import org.onap.cps.spi.exceptions.AlreadyDefinedExceptionBatch; import org.onap.cps.spi.exceptions.ConcurrencyException; import org.onap.cps.spi.exceptions.CpsAdminException; import org.onap.cps.spi.exceptions.CpsPathException; @@ -88,51 +89,75 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService Pattern.compile("\\[(\\@([^\\/]{0,9999}))\\]$"); @Override - @Transactional public void addChildDataNode(final String dataspaceName, final String anchorName, final String parentNodeXpath, final DataNode newChildDataNode) { - addChildDataNodes(dataspaceName, anchorName, parentNodeXpath, Collections.singleton(newChildDataNode)); + addNewChildDataNode(dataspaceName, anchorName, parentNodeXpath, newChildDataNode); } @Override - @Transactional public void addListElements(final String dataspaceName, final String anchorName, final String parentNodeXpath, final Collection newListElements) { - addChildDataNodes(dataspaceName, anchorName, parentNodeXpath, newListElements); + addChildrenDataNodes(dataspaceName, anchorName, parentNodeXpath, newListElements); } @Override - @Transactional - public void addListElementsBatch(final String dataspaceName, final String anchorName, final String parentNodeXpath, - final Collection> newListsElements) { + public void addMultipleLists(final String dataspaceName, final String anchorName, final String parentNodeXpath, + final Collection> newLists) { + final Collection failedCmHandleIds = new HashSet<>(); + newLists.forEach(newList -> { + try { + addChildrenDataNodes(dataspaceName, anchorName, parentNodeXpath, newList); + } catch (final AlreadyDefinedException e) { + newList.forEach(listElement -> failedCmHandleIds.add((String) listElement.getLeaves().get("id"))); + } + }); - newListsElements.forEach( - newListElement -> addListElements(dataspaceName, anchorName, parentNodeXpath, newListElement)); + if (!failedCmHandleIds.isEmpty()) { + throw new AlreadyDefinedExceptionBatch(failedCmHandleIds); + } } - private void addChildDataNodes(final String dataspaceName, final String anchorName, final String parentNodeXpath, - final Collection newChildren) { + private void addNewChildDataNode(final String dataspaceName, final String anchorName, + final String parentNodeXpath, final DataNode newChild) { final FragmentEntity parentFragmentEntity = getFragmentByXpath(dataspaceName, anchorName, parentNodeXpath); + final FragmentEntity newChildAsFragmentEntity = + convertToFragmentWithAllDescendants(parentFragmentEntity.getDataspace(), + parentFragmentEntity.getAnchor(), newChild); + newChildAsFragmentEntity.setParentId(parentFragmentEntity.getId()); + try { + fragmentRepository.save(newChildAsFragmentEntity); + } catch (final DataIntegrityViolationException e) { + throw AlreadyDefinedException.forDataNode(newChild.getXpath(), anchorName, e); + } + + } + + private void addChildrenDataNodes(final String dataspaceName, final String anchorName, final String parentNodeXpath, + final Collection newChildren) { + final FragmentEntity parentFragmentEntity = getFragmentByXpath(dataspaceName, anchorName, parentNodeXpath); + final List fragmentEntities = new ArrayList<>(newChildren.size()); try { - final List fragmentEntities = new ArrayList<>(); newChildren.forEach(newChildAsDataNode -> { - final FragmentEntity newChildAsFragmentEntity = convertToFragmentWithAllDescendants( - parentFragmentEntity.getDataspace(), - parentFragmentEntity.getAnchor(), - newChildAsDataNode); + final FragmentEntity newChildAsFragmentEntity = + convertToFragmentWithAllDescendants(parentFragmentEntity.getDataspace(), + parentFragmentEntity.getAnchor(), newChildAsDataNode); newChildAsFragmentEntity.setParentId(parentFragmentEntity.getId()); fragmentEntities.add(newChildAsFragmentEntity); }); fragmentRepository.saveAll(fragmentEntities); - } catch (final DataIntegrityViolationException exception) { - final List conflictXpaths = newChildren.stream() - .map(DataNode::getXpath) - .collect(Collectors.toList()); - throw AlreadyDefinedException.forDataNodes(conflictXpaths, anchorName, exception); + } catch (final DataIntegrityViolationException e) { + log.warn("Exception occurred : {} , Batch with size : {} will be retried using individual save operations", + e, fragmentEntities.size()); + retrySavingEachChildIndividually(dataspaceName, anchorName, parentNodeXpath, newChildren); } } + private void retrySavingEachChildIndividually(final String dataspaceName, final String anchorName, + final String parentNodeXpath, final Collection newChildren) { + newChildren.forEach(newChild -> addNewChildDataNode(dataspaceName, anchorName, parentNodeXpath, newChild)); + } + @Override public void storeDataNode(final String dataspaceName, final String anchorName, final DataNode dataNode) { final DataspaceEntity dataspaceEntity = dataspaceRepository.getByName(dataspaceName); -- cgit 1.2.3-korg