From 63aff8f081da3ca039bd7a29075f7edc495fb5b6 Mon Sep 17 00:00:00 2001 From: danielhanrahan Date: Wed, 21 Feb 2024 16:37:19 +0000 Subject: [PATCH] Improve performance of moduleSetTag lookup - Using absolute cps-path /dmi-registry/cm-handles is faster than descendant cps-path //cm-handles due to CPS-2087. - Converting DataNodes to YangModelCmHandle allows checking if the handles are READY without needing to send additional DB queries via cmHandleQueries::cmHandleHasState. Issue-ID: CPS-2027 Signed-off-by: danielhanrahan Change-Id: Ied7e884b0f779f394854603a7f8b186d09eb5be8 --- .../api/impl/inventory/sync/ModuleSyncService.java | 39 +++++++++++----------- .../inventory/sync/ModuleSyncServiceSpec.groovy | 12 ++++--- 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncService.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncService.java index 333a6f28b..dabfbbc6d 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncService.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncService.java @@ -31,7 +31,6 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Optional; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; @@ -113,34 +112,34 @@ public class ModuleSyncService { private ImmutableTriple, Collection> getAllModuleReferencesAndNewYangResourcesByModuleSetTag(final YangModelCmHandle yangModelCmHandle, final boolean inUpgrade) { - final String moduleSetTag = getModuleSetTag(yangModelCmHandle, inUpgrade); final Collection allModuleReferences; - Map newYangResources = Collections.emptyMap(); - - final Optional optionalDataNode = getFirstReadyDataNodeByModuleSetTagProvidedInDb(moduleSetTag); + final Map newYangResources; - if (optionalDataNode.isPresent()) { - log.info("Found other cm handle having same module set tag: {}", moduleSetTag); - final String otherAnchorWithSameModuleSetTag - = YangDataConverter.extractCmHandleIdFromXpath(optionalDataNode.get().getXpath()); - allModuleReferences = cpsModuleService.getYangResourcesModuleReferences( - NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, otherAnchorWithSameModuleSetTag); - } else { + final YangModelCmHandle cmHandleWithSameModuleSetTag = getAnyReadyCmHandleByModuleSetTag(moduleSetTag); + if (cmHandleWithSameModuleSetTag == null) { allModuleReferences = dmiModelOperations.getModuleReferences(yangModelCmHandle); newYangResources = getNewModuleNameToContentMap(yangModelCmHandle, allModuleReferences); + } else { + log.info("Found other cm handle having same module set tag: {}", moduleSetTag); + allModuleReferences = cpsModuleService.getYangResourcesModuleReferences( + NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, cmHandleWithSameModuleSetTag.getId()); + newYangResources = NO_NEW_MODULES; } return ImmutableTriple.of(moduleSetTag, newYangResources, allModuleReferences); } - private Optional getFirstReadyDataNodeByModuleSetTagProvidedInDb(final String moduleSetTag) { - final List dataNodes = StringUtils.isNotBlank(moduleSetTag) ? cmHandleQueries - .queryNcmpRegistryByCpsPath("//cm-handles[@module-set-tag='" + moduleSetTag + "']", - FetchDescendantsOption.OMIT_DESCENDANTS) : Collections.emptyList(); - return dataNodes.stream().filter(dataNode -> { - final String cmHandleId = YangDataConverter.extractCmHandleIdFromXpath(dataNode.getXpath()); - return cmHandleQueries.cmHandleHasState(cmHandleId, CmHandleState.READY); - }).findFirst(); + private YangModelCmHandle getAnyReadyCmHandleByModuleSetTag(final String moduleSetTag) { + if (StringUtils.isBlank(moduleSetTag)) { + return null; + } + final String escapedModuleSetTag = moduleSetTag.replace("'", "''"); + final List dataNodes = cmHandleQueries.queryNcmpRegistryByCpsPath( + NCMP_DMI_REGISTRY_PARENT + "/cm-handles[@module-set-tag='" + escapedModuleSetTag + "']", + FetchDescendantsOption.DIRECT_CHILDREN_ONLY); + return dataNodes.stream().map(YangDataConverter::convertCmHandleToYangModel) + .filter(cmHandle -> cmHandle.getCompositeState().getCmHandleState() == CmHandleState.READY) + .findFirst().orElse(null); } private void setCmHandleModuleSetTag(final YangModelCmHandle upgradedCmHandle, final String moduleSetTag) { diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncServiceSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncServiceSpec.groovy index bc1f9dcc9..6ab2d547e 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncServiceSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncServiceSpec.groovy @@ -26,7 +26,6 @@ import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NFP_OPE import static org.onap.cps.ncmp.api.impl.inventory.LockReasonCategory.MODULE_UPGRADE import org.onap.cps.ncmp.api.impl.inventory.CmHandleState -import org.onap.cps.spi.FetchDescendantsOption import org.onap.cps.spi.model.DataNode import org.onap.cps.api.CpsDataService import org.onap.cps.api.CpsModuleService @@ -55,7 +54,10 @@ class ModuleSyncServiceSpec extends Specification { mockCmHandleQueries, mockCpsDataService, mockCpsAnchorService, mockJsonObjectMapper) def expectedDataspaceName = NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME - def static cmHandleWithModuleSetTag = new DataNodeBuilder().withXpath("//cm-handles[@module-set-tag='tag-1'][@id='otherId']").withAnchor('otherId').build() + def static cmHandleWithModuleSetTag = new DataNodeBuilder() + .withXpath("/dmi-registry/cm-handles[@id='otherId']") + .withLeaves(['id': 'otherId', 'module-set-tag': 'tag-1']) + .withAnchor('otherId').build() def 'Sync model for a NEW cm handle using module set tags: #scenario.'() { given: 'a cm handle state to be synced' @@ -102,7 +104,7 @@ class ModuleSyncServiceSpec extends Specification { and: 'CPS-Core returns list of existing module resources for TBD' mockCpsModuleService.getYangResourcesModuleReferences(*_) >> [ new ModuleReference('module1','1') ] and: 'system contains #existingCmHandlesWithSameTag.size() cm handles with same tag' - mockCmHandleQueries.queryNcmpRegistryByCpsPath("//cm-handles[@module-set-tag='tag-1']", FetchDescendantsOption.OMIT_DESCENDANTS) >> existingCmHandlesWithSameTag + mockCmHandleQueries.queryNcmpRegistryByCpsPath(*_) >> existingCmHandlesWithSameTag and: 'the other cm handle is a state ready' mockCmHandleQueries.cmHandleHasState('otherId', CmHandleState.READY) >> true when: 'module sync is triggered' @@ -131,8 +133,8 @@ class ModuleSyncServiceSpec extends Specification { def moduleReferences = [new ModuleReference('module1', '1'), new ModuleReference('module2', '2')] mockCpsModuleService.getYangResourcesModuleReferences(*_)>> moduleReferences and: 'a cm handle with the same moduleSetTag can be found in the registry' - mockCmHandleQueries.queryNcmpRegistryByCpsPath("//cm-handles[@module-set-tag='targetModuleSetTag']", - FetchDescendantsOption.OMIT_DESCENDANTS) >> [new DataNode(xpath: '/dmi-registry/cm-handles[@id=\'cmHandleId-1\']', leaves: ['id': 'cmHandleId-1', 'cm-handle-state': 'READY'])] + mockCmHandleQueries.queryNcmpRegistryByCpsPath(*_) >> [new DataNode(xpath: '/dmi-registry/cm-handles[@id=\'cmHandleId-1\']', leaves: ['id': 'cmHandleId-1'], + childDataNodes: [new DataNode(xpath: '/dmi-registry/cm-handles[@id=\'cmHandleId-1\']/state', leaves: ['cm-handle-state': 'READY'])])] when: 'module upgrade is triggered' objectUnderTest.syncAndCreateOrUpgradeSchemaSetAndAnchor(yangModelCmHandle) then: 'the upgrade is delegated to the module service (with the correct parameters)' -- 2.16.6