Skip to content
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

Remove unlimited collections from the repository API #496

Merged
merged 36 commits into from
May 9, 2017

Conversation

kaizimmerm
Copy link
Contributor

@kaizimmerm kaizimmerm commented Apr 25, 2017

hawkBit in many areas of the repository returns unpaged and unlimited collections. This has a risk as the system will be asked to query huge collections of data in certain scenarios. Query 500k entities in one query for sure will have negative impact on the overall system. I can't even say what will explode first (persistence, Java Heap, APIs...).

Examples on the entity APIs itself are:

  • Action: List getActionStatus();
  • DistributionSet: Set getTags();

Examples on repository APIs:

  • DeploymentManagement: List findActiveActionsByTarget(@notempty String controllerId);
  • TargetManagement: List findTargetsByTag(@notempty String tagName);

Well, the risk is different depending on the use case. While active actions on a target should in most cases be a two digit number max it is not actually guaranteed. All targets assigned to a tag however might easily go in the 6 digit direction.

I fixed most scenarios by means of providing or using repository APIs with limits. There are some left. Here, however I believe we should introduce configurable quotas (e.g. how many software modules can be in a distribution set). Until then the risk stays in the system.

However, unfortunately on the public APIs we are propagating unpaged access as well (targets or DS assigned to a tag):

  • I created new resources with proper paging and restricted the other to 500 entities max and declared them deprecated.
  • One API call (remove all targets/DSs from a tag) could not be fixed. I removed it. Technically an API break but I think the use case of that resource is highly questionable (better delete the tag and create a new one).
  • While looking for tests that have to be aligned I figured that tests for tag resources in mgmt API where completely missing. I added those as well.

On the way I fixed a few typos in events and provided a proper API for the quotas we already have in the system. Should be quite easy to extend those in the future.

Note: this is another task of #197

Reviewers: @schabdo @sirwayne

kaizimmerm and others added 24 commits March 31, 2017 17:36
Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>
Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>
Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>
Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>
Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>
Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>
Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>
Conflicts:
	hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiCancelActionTest.java
	hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiDeploymentBaseTest.java
	hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/autoassign/AutoAssignScheduler.java
	hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rollout/RolloutScheduler.java
	hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/DeploymentManagementTest.java
Conflicts:
	hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/DistributionSetTagRepository.java
	hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetManagement.java
	hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaSystemManagement.java
	hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java
	hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TargetTagRepository.java
	hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/JpaTestRepositoryManagement.java
Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>
Conflicts:
	hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/integration/AmqpMessageHandlerServiceIntegrationTest.java

Signed-off-by: SirWayne <dennis.melzer@bosch-si.com>
Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>
Conflicts:
	hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/integration/AmqpMessageHandlerServiceIntegrationTest.java
	hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/DistributionSetRepository.java
Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>
Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>
Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>
Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>
Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>
Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>
Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>
Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>
Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>
Conflicts:
	hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/integration/AmqpMessageHandlerServiceIntegrationTest.java
@@ -110,9 +120,14 @@
public static final String TARGET_FILTER_V1_REQUEST_MAPPING = BASE_V1_REQUEST_MAPPING + "/targetfilters";

/**
* The deprecated tag URL mapping rest resource.
*/
public static final String DEPRECATED_DISTRIBUTIONSET_REQUEST_MAPPING = "/{distributionsetTagId}/distributionsets";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add @Deprecated

static Sort sanitizeTagSortParam(final String sortParam) {
if (sortParam == null) {
// default
return new Sort(Direction.ASC, TargetFields.NAME.getFieldName());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use TageFields.Name instead of Target


import org.eclipse.hawkbit.security.HawkbitSecurityProperties;

public class StaticQuotaManagement implements QuotaManagement {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Add javadoc
  2. I would rename the class to PropertiesQuotaManagement, because you use properties for the quota

*/
public static void verifyRolloutGroupParameter(final int amountGroup) {
public static void verifyRolloutGroupParameter(final int amountGroup, final int maxGroups) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my opinion it's better to make a real bean and inject the QuotaManagement here. Because now every developer can set another maxGroups constraint for every call.

if (!tag.isPresent()) {
return Collections.emptyList();
public Page<Target> findTargetsByTag(final Pageable pageable, final Long tagId) {
if (!targetTagRepository.exists(tagId)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

create a private method to avoid duplicate code

Conflicts:
	hawkbit-dmf-parent/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/integration/AmqpMessageHandlerServiceIntegrationTest.java
Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>
@kaizimmerm
Copy link
Contributor Author

kaizimmerm commented Apr 28, 2017

@sirwayne I like your ideas. All implemented.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>
Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>
Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>
Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>
Conflicts:
	hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiArtifactDownloadTest.java
Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>
@@ -316,31 +316,38 @@ private void waitUntilRolloutIsReady(final Long id) {

private void createDistributionSets(final Scenario scenario) {
LOGGER.info("Creating {} distribution sets", scenario.getDistributionSets());
final int pages = (scenario.getDistributionSets() / PAGE_SIZE) >= 1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The page calculation is broken when you slightly exceed the page size. For example: 506 or 501 distribution sets will result in a page size of 1 so in the end this code creates only 500 entities and not the expected amount.

Same happens to the other entities e.g. targets so I won't comment it there as well

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm afraid it is still broken. Use BigDecimal instead if int or float for the calculation.

Example:
new BigDecimal(1002).divide(new BigDecimal(500), BigDecimal.ROUND_UP) => 3

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>
.withRel("assignedTargets"));
response.add(linkTo(methodOn(MgmtTargetTagRestApi.class).getAssignedTargets(targetTag.getId(),
Integer.parseInt(MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET),
Integer.parseInt(MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT), null, null))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is an int value already available: Use MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT_VALUE instead of parsing the string

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting. I did not know that we have this value constant. I fixed this on all the mappers and created one for the offset as well.

methodOn(MgmtDistributionSetTagRestApi.class).getAssignedDistributionSets(distributionSetTag.getId()))
response.add(linkTo(methodOn(MgmtDistributionSetTagRestApi.class).getAssignedDistributionSets(
distributionSetTag.getId(), Integer.parseInt(MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET),
Integer.parseInt(MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT), null, null))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here

// OK
}

assertThatExceptionOfType(EntityAlreadyExistsException.class)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool 👍


public class JpaTestRepositoryManagement implements TestRepositoryManagement {

private static final Logger LOGGER = LoggerFactory.getLogger(JpaTestRepositoryManagement.class);
private static final Pageable pageReq = new PageRequest(0, 400, new Sort(Direction.ASC, "id"));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use CAPITAL LETTERS for variable pageReq => it is a constant

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copied from abstract integration test :) I will fix this in both classes.

*/
public List<DistributionSet> createDistributionSetsWithoutModules(final int number) {

final List<DistributionSet> sets = new ArrayList<>();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Set size of list => new ArrayList<>(number)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That does not help much. Lists.newArrayListWithExpectedSize(number) is the right one. But you are generally right of course.

try {
createTagLine(builder, tag);
} catch (final Exception e) {
e.printStackTrace();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not throwing an exception here? It's obviously wrong JSON. It might be easier to find when you stop processing the tags here instead of waiting for the test to fail due to missing tags later

Copy link
Contributor Author

@kaizimmerm kaizimmerm May 6, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, the code is copied from the other builders but I actually don't know why the exception is catched. I will fix this in the entire class.

kaizimmerm added 3 commits May 6, 2017 08:52
Conflicts:
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionTable.java
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionTableLayout.java
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rollout/DefineGroupsLayout.java
Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>
Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>
@kaizimmerm kaizimmerm merged commit c18e9f5 into eclipse-hawkbit:master May 9, 2017
@kaizimmerm kaizimmerm deleted the fix_memory_repo branch May 9, 2017 14:40
kinbod added a commit to kinbod/hawkbit that referenced this pull request May 10, 2017
Remove unlimited collections from the repository API (eclipse-hawkbit#496)
@kaizimmerm kaizimmerm added this to the 0.2.0M4 milestone Feb 7, 2018
AmmarBikic pushed a commit to bosch-io/hawkbit that referenced this pull request Oct 2, 2020
…#496)

* Started to get rid of unlimited collections

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Align API usage.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* fix compile issues.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Fix tests.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Remove comments

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Performance optimizations.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Remove dead code.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Allign method names

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Wait until the action update event is processed

Conflicts:
	hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/integration/AmqpMessageHandlerServiceIntegrationTest.java

Signed-off-by: SirWayne <dennis.melzer@bosch-si.com>

* Started new tag APIs

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Quotas into central interface. Tag tests added. Event names fixed.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Simplified consumer run for every tenant.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* remove unused fields.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Alligned beans.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Deprecated client methods for old resources.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Fix new foreach method.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Fix transaction for foreach.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Extended DS creating to handle larger volumes. Fix on Readme.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Fixed simulator bug and cleaned up tests.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Fix in sorting.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Remove configuration processor.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Fix wrong usage of sanitize.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Missing brackets.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Fix README API compatability.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Fix misinterpretation of pessimistic locking exceptions.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Fix stability sentence.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Code cleanup.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Fixed page calculation

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants