Skip to content

HDDS-16045. Make PendingContainerTracker StorageType aware - #10928

Draft
F64116045 wants to merge 639 commits into
apache:HDDS-11233from
F64116045:HDDS-16045-pending-container-storage-type
Draft

HDDS-16045. Make PendingContainerTracker StorageType aware#10928
F64116045 wants to merge 639 commits into
apache:HDDS-11233from
F64116045:HDDS-16045-pending-container-storage-type

Conversation

@F64116045

@F64116045 F64116045 commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

What changes were proposed in this pull request?

PendingContainerTracker currently accounts pending container allocations at the datanode level. With storage policy support, pending allocations should be counted only against the StorageType they target. For example, a pending DISK allocation should not reduce the available space calculated for SSD or ARCHIVE allocations.

This PR makes PendingContainerTracker store the StorageType for each pending container allocation. It adds StorageType-aware APIs in PendingContainerTracker and NodeManager, while keeping the existing untyped APIs and behavior for callers that do not have storage tier information.

PipelineManager derives the StorageType from the pipeline StorageTier and passes it to NodeManager when checking space and recording pending allocations.

The tests cover StorageType-specific pending counts, StorageType-specific space checks, the existing untyped behavior, and propagation from StorageTier.DISK to StorageType.DISK.

What is the link to the Apache JIRA

https://issues.apache.org/jira/browse/HDDS-16045

How was this patch tested?

  • mvn -B --no-transfer-progress -pl hadoop-hdds/server-scm -am -Dtest=TestPendingContainerTracker test -DskipShade -DskipRecon -DskipDocs

CI: https://github.com/F64116045/ozone/actions/runs/30770518425

szetszwo and others added 30 commits July 4, 2026 07:44
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…+ AGENTS.md) (apache#10483)

Co-authored-by: Siyao Meng <50227127+smengcl@users.noreply.github.com>
…he#10584)

Co-authored-by: Doroszlai, Attila <adoroszlai@apache.org>
Generated-by: Codex (GPT-5.3-Codex, GPT-5.4), Claude Code (Opus 4.8)

@xichen01 xichen01 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@F64116045 Thanks for you patch, left some comments

/**
* Add container to current window.
*/
synchronized boolean add(ContainerID containerID) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

this old method can be removed.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Removed the untyped add(...) method. Thanks.

}

@Override
public void recordPendingAllocationForDatanode(DatanodeID datanodeID, ContainerID containerID) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This can be removed too, make that recordPendingAllocationForDatanode must pass a storageType

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Removed the untyped recordPendingAllocationForDatanode(...); callers now pass StorageType. Thanks.

@@ -189,6 +190,14 @@ default int getAllNodeCount() {
*/
boolean hasSpaceForNewContainerAllocation(DatanodeID datanodeID);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

To prevent callers from forgetting to pass the storageType parameter, we should retain only the hasSpaceForNewContainerAllocation method that includes storageType.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Removed the untyped space-check API so callers need to pass StorageType.

}

containerStateManager.addContainer(containerInfoBuilder.build());
pipelineManager.recordPendingAllocation(pipeline, containerID);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

allocateContainer can be executed in parallel;
pipelineManager.hasEnoughSpace and pipelineManager.recordPendingAllocation are not protected by locks. In some cases, a DN may be allocated too many containers.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Addressed by adapting the atomic checkSpaceAndRecordAllocation(...) flow after updating from the latest HDDS-11233 branch. Thanks.

@devmadhuu

Copy link
Copy Markdown
Contributor

Added HDDS-16116 for rebasing HDDS-11233 feature branch with master. Keep hold till rebase finished.

@devmadhuu

Copy link
Copy Markdown
Contributor

@F64116045 I updated the shared feature branch HDDS-11233 on apache/ozone master to bring it up to date with master. The branch now = the original feature commits (unchanged SHAs) with a single Merge 'upstream/master' commit on top. New tip: 8decb32. Kindly do merge of this feature branch to your PR branch and resolve the conflicts.

…nding-container-storage-type

# Conflicts:
#	hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/node/NodeManager.java
#	hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/node/PendingContainerTracker.java
#	hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/node/SCMNodeManager.java
#	hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/pipeline/PipelineManagerImpl.java
#	hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/MockNodeManager.java
#	hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/node/TestPendingContainerTracker.java
#	hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/pipeline/MockPipelineManager.java
#	hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/pipeline/TestPipelineManagerImpl.java
@F64116045

Copy link
Copy Markdown
Contributor Author

@devmadhuu Thanks for helping with the feature branch update.

I noticed HDDS-11233 is now back at ed07a4b, while this PR already merged 8decb32, so the diff became very large.

Should I wait for HDDS-11233 to be updated again, or rework this PR on the current base?

@devmadhuu

Copy link
Copy Markdown
Contributor

@devmadhuu Thanks for helping with the feature branch update.

I noticed HDDS-11233 is now back at ed07a4b, while this PR already merged 8decb32, so the diff became very large.

Should I wait for HDDS-11233 to be updated again, or rework this PR on the current base?

Apologies for this confusion. Yes I rebased and force pushed the HDDS-11233 , but we need to follow the merge process instead of rebase for feature branches and raise PRs and follow the normal PR process. So I reverted the earlier forced push and now raised this PR #10983
Kindly wait till this PR gets merged.

@devmadhuu

Copy link
Copy Markdown
Contributor

@devmadhuu Thanks for helping with the feature branch update.
I noticed HDDS-11233 is now back at ed07a4b, while this PR already merged 8decb32, so the diff became very large.
Should I wait for HDDS-11233 to be updated again, or rework this PR on the current base?

Apologies for this confusion. Yes I rebased and force pushed the HDDS-11233 , but we need to follow the merge process instead of rebase for feature branches and raise PRs and follow the normal PR process. So I reverted the earlier forced push and now raised this PR #10983 Kindly wait till this PR gets merged.

@F64116045 #10983 is merged.

…nding-container-storage-type

# Conflicts:
#	hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/SCMCommonPlacementPolicy.java
#	hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/ha/invoker/ContainerStateManagerInvoker.java
#	hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/node/NodeManager.java
#	hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/node/PendingContainerTracker.java
#	hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/node/SCMNodeManager.java
#	hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/pipeline/ECPipelineProvider.java
#	hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/pipeline/PipelineManagerImpl.java
#	hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/pipeline/SimplePipelineProvider.java
#	hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/TestSCMCommonPlacementPolicy.java
#	hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/MockNodeManager.java
#	hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/SimpleMockNodeManager.java
#	hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/placement/algorithms/TestContainerPlacementFactory.java
#	hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/placement/algorithms/TestSCMContainerPlacementCapacity.java
#	hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/placement/algorithms/TestSCMContainerPlacementRackAware.java
#	hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/placement/algorithms/TestSCMContainerPlacementRackScatter.java
#	hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/placement/algorithms/TestSCMContainerPlacementRandom.java
#	hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/node/TestPendingContainerTracker.java
#	hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/pipeline/MockPipelineManager.java
#	hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/pipeline/TestPipelineManagerImpl.java
#	hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/pipeline/TestPipelinePlacementFactory.java
@F64116045
F64116045 marked this pull request as draft August 19, 2026 00:24
@F64116045

Copy link
Copy Markdown
Contributor Author

Following the discussion in apache/ozone#10983, I also moved the data-space check from SCMCommonPlacementPolicy into PendingContainerTracker.

Previously, SCMCommonPlacementPolicy did this check directly.

Now SCMCommonPlacementPolicy delegates to NodeManager.hasAvailableSpace(...), and the combined check lives in PendingContainerTracker.

@F64116045

Copy link
Copy Markdown
Contributor Author

Thanks everyone for the guidance. Since the diff became larger after syncing the feature branch and addressing the review comments, I wanted to summarize the current patch to make review easier.

The main changes are:

  • PendingContainerTracker now records pending allocations with StorageType and counts them per requested storage type.
  • Container allocation uses the atomic checkSpaceAndRecordAllocation(...) flow and passes the StorageType derived from the pipeline StorageTier.
  • Pending allocations are removed when container reports confirm the container as present or absent on the datanode.
  • Following the discussion in HDDS-16116. Merge recent commits from master to HDDS-11233 #10983, the data-space check was moved from SCMCommonPlacementPolicy into PendingContainerTracker, exposed through NodeManager.hasAvailableSpace(...).

Most of the remaining test changes are mechanical updates for the new method signatures. The main behavioral tests are in:

  • TestPendingContainerTracker
  • TestPipelineManagerImpl
  • TestSCMNodeManager
  • TestSCMCommonPlacementPolicy

I ran the targeted SCM tests locally and will keep an eye on CI, thanks.

@F64116045
F64116045 marked this pull request as ready for review August 19, 2026 15:16

@devmadhuu devmadhuu left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks @F64116045 for addressing the review comments and rebase with latest upstream feature branch.. Just few nits. Please check.

@ashishkumar50 request you also to kindly re-review after merge master with latest upstream feature branch.

DatanodeInfo dnInfo = getNode(op.getTarget().getID());
if (dnInfo != null) {
recordAllocationForDatanode(dnInfo, containerID);
recordAllocationForDatanode(dnInfo, containerID, StorageType.DEFAULT);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This sending StorageType.DEFAULT may not be correct as every incoming req from RM / balancer will account for space under DISK tier. Can we pass the real tier based on containerInfo from the caller of this: org.apache.hadoop.hdds.scm.container.replication.ReplicationManager#adjustPendingOpsAndMetrics

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks for catching. I missed that path. Fixed.
It now carries the type from containerInfo instead of defaulting in opAdded. Added a small SSD test too.

if (storageTier == null || storageTier == StorageTier.EMPTY) {
return null;
}
return storageTier.getUniformStorageType();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Though once pipeline gets created with a specific tier at pipeline creation time, but here using primary storage type only and no fallback for space pending allocation is okay ? for SSD tier, this returns ONLY "SSD" Just a doubt.. @ivandika3 @xichen01

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks for raising this.
The existing pipeline selection path also maps the tier through storageTier.getUniformStorageType() in RatisPipelineProvider and PipelineProvider and there is no fallback, so I think it is acceptable here?

(If fallback should be handled differently, I’m happy to update it, thanks.)

@ashishkumar50 ashishkumar50 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@F64116045 Thanks for the update, please find comments inline:

// Always slot-based (maxContainerSize unit).
if (!nodeManager.hasAvailableSpace(datanodeInfo)) {
if (!nodeManager.hasAvailableSpace(
datanodeInfo, dataSizeRequired, storageType)) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

dataSizeRequired is not required.

private Set<ContainerID> currentWindow = new HashSet<>();
private Set<ContainerID> previousWindow = new HashSet<>();
private Map<ContainerID, StorageType> currentWindow = new HashMap<>();
private Map<ContainerID, StorageType> previousWindow = new HashMap<>();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Instead of doing like this, storing each container and its storageType. Instead we can make TwoWindowBucket as storageType for each datanode.

DataNode1:
 ├── DISK     -> TwoWindowBucket
 └── SSD      -> TwoWindowBucket
DataNode2:
 ├── DISK     -> TwoWindowBucket
 └── SSD      -> TwoWindowBucket

*/
private boolean hasEnoughSpaceForNode(DatanodeInfo dn) {
if (!tracker.hasAvailableSpace(dn)) {
if (!tracker.hasAvailableSpace(dn, 0, null)) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No need to pass 0 here.


@Override
public boolean checkSpaceAndRecordAllocation(Pipeline pipeline, ContainerID containerID) {
StorageType storageType = getStorageTypeForPendingAllocation(pipeline);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

What does it mean here getStorageTypeForPendingAllocation ? It just give storageType for pipeline, if so we can just rename getStorageType(pipeline).

@F64116045
F64116045 marked this pull request as draft August 26, 2026 00:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.