Fragment handling decreasing performance for large number of cmHandles 82/127082/8
authorDylanB95EST <dylan.byrne@est.tech>
Fri, 11 Feb 2022 12:46:27 +0000 (12:46 +0000)
committerDylan Byrne <dylan.byrne@est.tech>
Tue, 15 Feb 2022 14:49:57 +0000 (14:49 +0000)
- 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 <dylan.byrne@est.tech>
cps-ri/src/main/java/org/onap/cps/spi/entities/FragmentEntity.java
cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java
cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceIntegrationSpec.groovy
csit/plans/cps/pnfsim/netconf-config/stores.yang

index 00d1d98..2fdfa05 100755 (executable)
@@ -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;
index ed414fc..0480472 100644 (file)
@@ -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<DataNode> dataNodes) {
-        final FragmentEntity parentFragment = getFragmentByXpath(dataspaceName, anchorName, parentNodeXpath);
-        final List<FragmentEntity> newFragmentEntities =
-            dataNodes.stream().map(
-                dataNode -> toFragmentEntity(parentFragment.getDataspace(), parentFragment.getAnchor(), dataNode)
-            ).collect(Collectors.toUnmodifiableList());
-        parentFragment.getChildFragments().addAll(newFragmentEntities);
+        final Collection<DataNode> newListElements) {
+        addChildDataNodes(dataspaceName, anchorName, parentNodeXpath, newListElements);
+    }
+
+    private void addChildDataNodes(final String dataspaceName, final String anchorName, final String parentNodeXpath,
+                                final Collection<DataNode> 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<String> conflictXpaths = dataNodes.stream()
+            final List<String> 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()
index 41e7a41..2277377 100755 (executable)
@@ -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])
index b24ac0e..59051f2 100644 (file)
@@ -1,63 +1,63 @@
-module stores {\r
-\r
-    yang-version 1.1;\r
-\r
-    namespace "org:onap:ccsdk:sample";\r
-\r
-    prefix book-store;\r
-\r
-       import ietf-yang-types { prefix yang; }\r
-       import ietf-inet-types { prefix inet; }\r
-\r
-    revision "2020-09-15" {\r
-        description\r
-        "Sample Model";\r
-    }\r
-\r
-    typedef year {\r
-        type uint16 {\r
-            range "1000..9999";\r
-        }\r
-    }\r
-\r
-    container bookstore {\r
-\r
-        leaf bookstore-name {\r
-            type string;\r
-        }\r
-\r
-        list categories {\r
-\r
-            key "code";\r
-\r
-            leaf code {\r
-                type string;\r
-            }\r
-\r
-            leaf name {\r
-                type string;\r
-            }\r
-\r
-            list books {\r
-                key title;\r
-\r
-                leaf title {\r
-                    type string;\r
-                }\r
-                leaf lang {\r
-                    type string;\r
-                }\r
-                leaf-list authors {\r
-                    type string;\r
-                }\r
-                leaf pub_year {\r
-                     type year;\r
-                }\r
-                leaf price {\r
-                     type uint64;\r
-                }\r
-            }\r
-        }\r
-   }\r
-}\r
-\r
+module stores {
+
+    yang-version 1.1;
+
+    namespace "org:onap:ccsdk:sample";
+
+    prefix book-store;
+
+       import ietf-yang-types { prefix yang; }
+       import ietf-inet-types { prefix inet; }
+
+    revision "2020-09-15" {
+        description
+        "Sample Model";
+    }
+
+    typedef year {
+        type uint16 {
+            range "1000..9999";
+        }
+    }
+
+    container bookstore {
+
+        leaf bookstore-name {
+            type string;
+        }
+
+        list categories {
+
+            key "code";
+
+            leaf code {
+                type string;
+            }
+
+            leaf name {
+                type string;
+            }
+
+            list books {
+                key title;
+
+                leaf title {
+                    type string;
+                }
+                leaf lang {
+                    type string;
+                }
+                leaf-list authors {
+                    type string;
+                }
+                leaf pub_year {
+                     type year;
+                }
+                leaf price {
+                     type uint64;
+                }
+            }
+        }
+   }
+}
+