-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
listNetworks optimization #9096
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2267,7 +2267,7 @@ public Pair<List<? extends Network>, Integer> searchForNetworks(ListNetworksCmd | |
isRecursive = true; | ||
} | ||
|
||
Filter searchFilter = new Filter(NetworkVO.class, "id", false, null, null); | ||
Filter searchFilter = new Filter(NetworkVO.class, "id", false, cmd.getStartIndex(), cmd.getPageSizeVal()); | ||
SearchBuilder<NetworkVO> sb = _networksDao.createSearchBuilder(); | ||
|
||
if (forVpc != null) { | ||
|
@@ -2322,41 +2322,52 @@ public Pair<List<? extends Network>, Integer> searchForNetworks(ListNetworksCmd | |
sb.join("associatedNetworkSearch", associatedNetworkSearch, sb.entity().getId(), associatedNetworkSearch.entity().getResourceId(), JoinBuilder.JoinType.INNER); | ||
} | ||
|
||
List<NetworkVO> networksToReturn = new ArrayList<NetworkVO>(); | ||
Pair<List<NetworkVO>, Integer> networks; | ||
Pair<List<NetworkVO>, Integer> networksToReturn = new Pair<>(new ArrayList<NetworkVO>(), 0); | ||
|
||
if (isSystem == null || !isSystem) { | ||
if (!permittedAccounts.isEmpty()) { | ||
if (Arrays.asList(Network.NetworkFilter.Account, Network.NetworkFilter.AccountDomain, Network.NetworkFilter.All).contains(networkFilter)) { | ||
//get account level networks | ||
networksToReturn.addAll(listAccountSpecificNetworks(buildNetworkSearchCriteria(sb, keyword, id, isSystem, zoneId, guestIpType, trafficType, physicalNetworkId, networkOfferingId, | ||
aclType, skipProjectNetworks, restartRequired, specifyIpRanges, vpcId, tags, display, vlanId, associatedNetworkId), searchFilter, permittedAccounts)); | ||
networks = listAccountSpecificNetworks(buildNetworkSearchCriteria(sb, keyword, id, isSystem, zoneId, guestIpType, trafficType, physicalNetworkId, networkOfferingId, | ||
aclType, skipProjectNetworks, restartRequired, specifyIpRanges, vpcId, tags, display, vlanId, associatedNetworkId), searchFilter, permittedAccounts); | ||
networksToReturn.first().addAll(networks.first()); | ||
networksToReturn.second(networksToReturn.second() + networks.second()); | ||
} | ||
if (domainId != null && Arrays.asList(Network.NetworkFilter.Domain, Network.NetworkFilter.AccountDomain, Network.NetworkFilter.All).contains(networkFilter)) { | ||
//get domain level networks | ||
networksToReturn.addAll(listDomainLevelNetworks(buildNetworkSearchCriteria(sb, keyword, id, isSystem, zoneId, guestIpType, trafficType, physicalNetworkId, networkOfferingId, | ||
aclType, true, restartRequired, specifyIpRanges, vpcId, tags, display, vlanId, associatedNetworkId), searchFilter, domainId, false)); | ||
networks = listDomainLevelNetworks(buildNetworkSearchCriteria(sb, keyword, id, isSystem, zoneId, guestIpType, trafficType, physicalNetworkId, networkOfferingId, | ||
aclType, true, restartRequired, specifyIpRanges, vpcId, tags, display, vlanId, associatedNetworkId), searchFilter, domainId, false); | ||
networksToReturn.first().addAll(networks.first()); | ||
networksToReturn.second(networksToReturn.second() + networks.second()); | ||
} | ||
if (Arrays.asList(Network.NetworkFilter.Shared, Network.NetworkFilter.All).contains(networkFilter)) { | ||
// get shared networks | ||
List<NetworkVO> sharedNetworks = listSharedNetworks(buildNetworkSearchCriteria(sb, keyword, id, isSystem, zoneId, guestIpType, trafficType, physicalNetworkId, networkOfferingId, | ||
Pair<List<NetworkVO>, Integer> sharedNetworks = listSharedNetworks(buildNetworkSearchCriteria(sb, keyword, id, isSystem, zoneId, guestIpType, trafficType, physicalNetworkId, networkOfferingId, | ||
aclType, true, restartRequired, specifyIpRanges, vpcId, tags, display, vlanId, associatedNetworkId), searchFilter, permittedAccounts); | ||
addNetworksToReturnIfNotExist(networksToReturn, sharedNetworks); | ||
addNetworksToReturnIfNotExist(networksToReturn, sharedNetworks.first()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The total count of result won't be super accurate now. But now we will be working with at max 20 account and domain level networks in the list. So there is no way to apply union with all the shared networks. For example, Before this change : After this change: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This needs to be accurate too. Perhaps once the query returns the page, we can call a dao::getCount() passing only the list of IDs? |
||
|
||
} | ||
} else { | ||
if (Arrays.asList(Network.NetworkFilter.Account, Network.NetworkFilter.AccountDomain, Network.NetworkFilter.All).contains(networkFilter)) { | ||
//add account specific networks | ||
networksToReturn.addAll(listAccountSpecificNetworksByDomainPath(buildNetworkSearchCriteria(sb, keyword, id, isSystem, zoneId, guestIpType, trafficType, physicalNetworkId, networkOfferingId, | ||
aclType, skipProjectNetworks, restartRequired, specifyIpRanges, vpcId, tags, display, vlanId, associatedNetworkId), searchFilter, path, isRecursive)); | ||
networks = listAccountSpecificNetworksByDomainPath(buildNetworkSearchCriteria(sb, keyword, id, isSystem, zoneId, guestIpType, trafficType, physicalNetworkId, networkOfferingId, | ||
aclType, skipProjectNetworks, restartRequired, specifyIpRanges, vpcId, tags, display, vlanId, associatedNetworkId), searchFilter, path, isRecursive); | ||
networksToReturn.first().addAll(networks.first()); | ||
networksToReturn.second(networksToReturn.second() + networks.second()); | ||
} | ||
if (Arrays.asList(Network.NetworkFilter.Domain, Network.NetworkFilter.AccountDomain, Network.NetworkFilter.All).contains(networkFilter)) { | ||
//add domain specific networks of domain + parent domains | ||
networksToReturn.addAll(listDomainSpecificNetworksByDomainPath(buildNetworkSearchCriteria(sb, keyword, id, isSystem, zoneId, guestIpType, trafficType, physicalNetworkId, networkOfferingId, | ||
aclType, true, restartRequired, specifyIpRanges, vpcId, tags, display, vlanId, associatedNetworkId), searchFilter, path, isRecursive)); | ||
networks = listDomainSpecificNetworksByDomainPath(buildNetworkSearchCriteria(sb, keyword, id, isSystem, zoneId, guestIpType, trafficType, physicalNetworkId, networkOfferingId, | ||
aclType, true, restartRequired, specifyIpRanges, vpcId, tags, display, vlanId, associatedNetworkId), searchFilter, path, isRecursive); | ||
networksToReturn.first().addAll(networks.first()); | ||
networksToReturn.second(networksToReturn.second() + networks.second()); | ||
//add networks of subdomains | ||
if (domainId == null) { | ||
networksToReturn.addAll(listDomainLevelNetworks(buildNetworkSearchCriteria(sb, keyword, id, isSystem, zoneId, guestIpType, trafficType, physicalNetworkId, networkOfferingId, | ||
aclType, true, restartRequired, specifyIpRanges, vpcId, tags, display, vlanId, associatedNetworkId), searchFilter, caller.getDomainId(), true)); | ||
networks = listDomainLevelNetworks(buildNetworkSearchCriteria(sb, keyword, id, isSystem, zoneId, guestIpType, trafficType, physicalNetworkId, networkOfferingId, | ||
aclType, true, restartRequired, specifyIpRanges, vpcId, tags, display, vlanId, associatedNetworkId), searchFilter, caller.getDomainId(), true); | ||
networksToReturn.first().addAll(networks.first()); | ||
networksToReturn.second(networksToReturn.second() + networks.second()); | ||
} | ||
} | ||
if (Arrays.asList(Network.NetworkFilter.Shared, Network.NetworkFilter.All).contains(networkFilter)) { | ||
|
@@ -2367,11 +2378,11 @@ public Pair<List<? extends Network>, Integer> searchForNetworks(ListNetworksCmd | |
} | ||
} | ||
} else { | ||
networksToReturn = _networksDao.search(buildNetworkSearchCriteria(sb, keyword, id, isSystem, zoneId, guestIpType, trafficType, physicalNetworkId, networkOfferingId, | ||
networksToReturn = _networksDao.searchAndCount(buildNetworkSearchCriteria(sb, keyword, id, isSystem, zoneId, guestIpType, trafficType, physicalNetworkId, networkOfferingId, | ||
null, true, restartRequired, specifyIpRanges, vpcId, tags, display, vlanId, associatedNetworkId), searchFilter); | ||
} | ||
|
||
if (supportedServicesStr != null && !supportedServicesStr.isEmpty() && !networksToReturn.isEmpty()) { | ||
if (supportedServicesStr != null && !supportedServicesStr.isEmpty() && !networksToReturn.first().isEmpty()) { | ||
List<NetworkVO> supportedNetworks = new ArrayList<NetworkVO>(); | ||
Service[] suppportedServices = new Service[supportedServicesStr.size()]; | ||
int i = 0; | ||
|
@@ -2385,44 +2396,45 @@ public Pair<List<? extends Network>, Integer> searchForNetworks(ListNetworksCmd | |
i++; | ||
} | ||
|
||
for (NetworkVO network : networksToReturn) { | ||
for (NetworkVO network : networksToReturn.first()) { | ||
if (areServicesSupportedInNetwork(network.getId(), suppportedServices)) { | ||
supportedNetworks.add(network); | ||
} | ||
} | ||
|
||
networksToReturn = supportedNetworks; | ||
networksToReturn.first(supportedNetworks); | ||
} | ||
|
||
if (canUseForDeploy != null) { | ||
List<NetworkVO> networksForDeploy = new ArrayList<NetworkVO>(); | ||
for (NetworkVO network : networksToReturn) { | ||
for (NetworkVO network : networksToReturn.first()) { | ||
if (_networkModel.canUseForDeploy(network) == canUseForDeploy) { | ||
networksForDeploy.add(network); | ||
} | ||
} | ||
|
||
networksToReturn = networksForDeploy; | ||
networksToReturn.first(networksForDeploy); | ||
} | ||
|
||
//Now apply pagination | ||
List<? extends Network> wPagination = com.cloud.utils.StringUtils.applyPagination(networksToReturn, cmd.getStartIndex(), cmd.getPageSizeVal()); | ||
List<? extends Network> wPagination = com.cloud.utils.StringUtils.applyPagination(networksToReturn.first(), cmd.getStartIndex(), cmd.getPageSizeVal()); | ||
if (wPagination != null) { | ||
Pair<List<? extends Network>, Integer> listWPagination = new Pair<List<? extends Network>, Integer>(wPagination, networksToReturn.size()); | ||
Pair<List<? extends Network>, Integer> listWPagination = new Pair<List<? extends Network>, Integer>(wPagination, networksToReturn.second()); | ||
return listWPagination; | ||
} | ||
|
||
return new Pair<List<? extends Network>, Integer>(networksToReturn, networksToReturn.size()); | ||
return new Pair<List<? extends Network>, Integer>(networksToReturn.first(), networksToReturn.second()); | ||
} | ||
|
||
private void addNetworksToReturnIfNotExist(final List<NetworkVO> networksToReturn, final List<NetworkVO> sharedNetworks) { | ||
Set<Long> networkIds = networksToReturn.stream() | ||
private void addNetworksToReturnIfNotExist(final Pair<List<NetworkVO>, Integer> networksToReturn, final List<NetworkVO> sharedNetworks) { | ||
Set<Long> networkIds = networksToReturn.first().stream() | ||
.map(NetworkVO::getId) | ||
.collect(Collectors.toSet()); | ||
List<NetworkVO> sharedNetworksToReturn = sharedNetworks.stream() | ||
.filter(network -> ! networkIds.contains(network.getId())) | ||
.collect(Collectors.toList()); | ||
networksToReturn.addAll(sharedNetworksToReturn); | ||
networksToReturn.first().addAll(sharedNetworksToReturn); | ||
networksToReturn.second(networksToReturn.second() + sharedNetworksToReturn.size()); | ||
} | ||
|
||
private SearchCriteria<NetworkVO> buildNetworkSearchCriteria(SearchBuilder<NetworkVO> sb, String keyword, Long id, | ||
|
@@ -2516,7 +2528,7 @@ private SearchCriteria<NetworkVO> buildNetworkSearchCriteria(SearchBuilder<Netwo | |
return sc; | ||
} | ||
|
||
private List<NetworkVO> listDomainLevelNetworks(SearchCriteria<NetworkVO> sc, Filter searchFilter, long domainId, boolean parentDomainsOnly) { | ||
private Pair<List<NetworkVO>, Integer> listDomainLevelNetworks(SearchCriteria<NetworkVO> sc, Filter searchFilter, long domainId, boolean parentDomainsOnly) { | ||
List<Long> networkIds = new ArrayList<Long>(); | ||
Set<Long> allowedDomains = _domainMgr.getDomainParentIds(domainId); | ||
List<NetworkDomainVO> maps = _networkDomainDao.listDomainNetworkMapByDomain(allowedDomains.toArray()); | ||
|
@@ -2537,13 +2549,13 @@ private List<NetworkVO> listDomainLevelNetworks(SearchCriteria<NetworkVO> sc, Fi | |
domainSC.addAnd("aclType", SearchCriteria.Op.EQ, ACLType.Domain.toString()); | ||
|
||
sc.addAnd("id", SearchCriteria.Op.SC, domainSC); | ||
return _networksDao.search(sc, searchFilter); | ||
return _networksDao.searchAndCount(sc, searchFilter); | ||
} else { | ||
return new ArrayList<NetworkVO>(); | ||
return new Pair<>(new ArrayList<NetworkVO>(), 0); | ||
} | ||
} | ||
|
||
private List<NetworkVO> listAccountSpecificNetworks(SearchCriteria<NetworkVO> sc, Filter searchFilter, List<Long> permittedAccounts) { | ||
private Pair<List<NetworkVO>, Integer> listAccountSpecificNetworks(SearchCriteria<NetworkVO> sc, Filter searchFilter, List<Long> permittedAccounts) { | ||
SearchCriteria<NetworkVO> accountSC = _networksDao.createSearchCriteria(); | ||
if (!permittedAccounts.isEmpty()) { | ||
accountSC.addAnd("accountId", SearchCriteria.Op.IN, permittedAccounts.toArray()); | ||
|
@@ -2552,10 +2564,10 @@ private List<NetworkVO> listAccountSpecificNetworks(SearchCriteria<NetworkVO> sc | |
accountSC.addAnd("aclType", SearchCriteria.Op.EQ, ACLType.Account.toString()); | ||
|
||
sc.addAnd("id", SearchCriteria.Op.SC, accountSC); | ||
return _networksDao.search(sc, searchFilter); | ||
return _networksDao.searchAndCount(sc, searchFilter); | ||
} | ||
|
||
private List<NetworkVO> listAccountSpecificNetworksByDomainPath(SearchCriteria<NetworkVO> sc, Filter searchFilter, String path, boolean isRecursive) { | ||
private Pair<List<NetworkVO>, Integer> listAccountSpecificNetworksByDomainPath(SearchCriteria<NetworkVO> sc, Filter searchFilter, String path, boolean isRecursive) { | ||
SearchCriteria<NetworkVO> accountSC = _networksDao.createSearchCriteria(); | ||
accountSC.addAnd("aclType", SearchCriteria.Op.EQ, ACLType.Account.toString()); | ||
|
||
|
@@ -2568,10 +2580,10 @@ private List<NetworkVO> listAccountSpecificNetworksByDomainPath(SearchCriteria<N | |
} | ||
|
||
sc.addAnd("id", SearchCriteria.Op.SC, accountSC); | ||
return _networksDao.search(sc, searchFilter); | ||
return _networksDao.searchAndCount(sc, searchFilter); | ||
} | ||
|
||
private List<NetworkVO> listDomainSpecificNetworksByDomainPath(SearchCriteria<NetworkVO> sc, Filter searchFilter, String path, boolean isRecursive) { | ||
private Pair<List<NetworkVO>, Integer> listDomainSpecificNetworksByDomainPath(SearchCriteria<NetworkVO> sc, Filter searchFilter, String path, boolean isRecursive) { | ||
|
||
Set<Long> allowedDomains = new HashSet<Long>(); | ||
if (path != null) { | ||
|
@@ -2597,21 +2609,21 @@ private List<NetworkVO> listDomainSpecificNetworksByDomainPath(SearchCriteria<Ne | |
domainSC.addAnd("aclType", SearchCriteria.Op.EQ, ACLType.Domain.toString()); | ||
|
||
sc.addAnd("id", SearchCriteria.Op.SC, domainSC); | ||
return _networksDao.search(sc, searchFilter); | ||
return _networksDao.searchAndCount(sc, searchFilter); | ||
} else { | ||
return new ArrayList<NetworkVO>(); | ||
return new Pair<>(new ArrayList<NetworkVO>(), 0); | ||
} | ||
} | ||
|
||
private List<NetworkVO> listSharedNetworks(SearchCriteria<NetworkVO> sc, Filter searchFilter, List<Long> permittedAccounts) { | ||
private Pair<List<NetworkVO>, Integer> listSharedNetworks(SearchCriteria<NetworkVO> sc, Filter searchFilter, List<Long> permittedAccounts) { | ||
List<Long> sharedNetworkIds = _networkPermissionDao.listPermittedNetworkIdsByAccounts(permittedAccounts); | ||
if (!sharedNetworkIds.isEmpty()) { | ||
SearchCriteria<NetworkVO> ssc = _networksDao.createSearchCriteria(); | ||
ssc.addAnd("id", SearchCriteria.Op.IN, sharedNetworkIds.toArray()); | ||
sc.addAnd("id", SearchCriteria.Op.SC, ssc); | ||
return _networksDao.search(sc, searchFilter); | ||
return _networksDao.searchAndCount(sc, searchFilter); | ||
} | ||
return new ArrayList<NetworkVO>(); | ||
return new Pair<>(new ArrayList<NetworkVO>(), 0); | ||
} | ||
|
||
private List<NetworkVO> listSharedNetworksByDomainPath(SearchCriteria<NetworkVO> sc, Filter searchFilter, String path, boolean isRecursive) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if networkfilter is Account, Domain or Shared, it should work
However, if the networkfilter is All or AccountDomain, it might not work if the searchFilter is the same
for example, there are 25 networks for account, 25 networks for domain. if networkfilter is All or AccountDomain, and the page size is 20,
I think the
searchFilter
needs to be updated after the each search.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a very good point.
The issue here is that we are concatenating results from multiple queries ( lest's say Q1, Q2, Q3). Things kind of work for the first page. We can adjust pageSize of a query depending on how many results are already returned for other queries.
But if we want to display the second page, it is hard to say which startIndex should be used for Q2. As it depends on how many results were displayed for Q2 on page 1. Which in turn depends on how many Q1 results were there on Page 1. For example, if page 1 had 15 results for Q1 and 5 results for Q2, then page2 Q2 startIndex should be 6.
So, to fix this I think the filter should always have
startIndex
as0
andpageSize
should becmd.getPageSizeVal() * (cmd.getStartIndex() + 1)
Filter searchFilter = new Filter(NetworkVO.class, "id", false, 0, (cmd.getStartIndex() + 1) * cmd.getPageSizeVal());
This way we have info on all previous page results and when pagination is applied at the end of the method, the correct result will be returned.
We are losing some optimization if startIndex is higher but it is still better than reading all rows.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are there not any other API similar to this where pagination is applied where the pattern can be repeated, maybe templates, volumes, offerings?