Skip to content

Commit

Permalink
Adds progress Allocation to represent Decentralized Allocation Tree n…
Browse files Browse the repository at this point in the history
  • Loading branch information
coollog committed Dec 5, 2018
1 parent 706f67c commit af93240
Show file tree
Hide file tree
Showing 2 changed files with 193 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*
* Copyright 2018 Google LLC.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/

package com.google.cloud.tools.jib.event.progress;

import java.util.Optional;
import javax.annotation.Nullable;

/**
* Represents a Decentralized Allocation Tree (DAT) node.
*
* <p>A DAT node is immutable and pointers only go in the direction from child to parent. Each node
* has a set number of allocated units, the total of which represents a single allocation unit of
* its parent. Each node is therefore a sub-allocation of its parent node. This allows the DAT to
* sub-allocate progress in a decentralized, asynchronous manner.
*
* <p>For example, thread 1 creates node A as the root node with 2 allocation units. A subtask is
* launched on thread 1 and creates node B with 3 allocation units as a child of node A. Thread 1
* then also launches a subtask on thread 2 that creates node C with 5 allocation units. Once the
* first subtask finishes and reports its progress, that completion would entail completion of 3
* allocation units of node B and 1 allocation unit of node A. The second subtask finishes and
* reports its progress as well, indicating completion of 5 units of node C and thus 1 unit of node
* A. Allocation A is then deemed complete as well in terms of overall progress.
*
* <p>Note that it is up to the user of the class to ensure that the number of sub-allocations does
* not exceed the number of allocation units.
*/
class Allocation {

/**
* Creates a new root {@link Allocation}.
*
* @param description thuser-facing description of what the allocation represents
* @param allocationUnits number of allocation units
* @return a new {@link Allocation}
*/
static Allocation newRoot(String description, long allocationUnits) {
return new Allocation(description, allocationUnits, null);
}

/** The parent {@link Allocation}, or {@code null} to indicate a root node. */
@Nullable private final Allocation parent;

/** User-facing description of what the allocation represents. */
private final String description;

/** The number of allocation units this node holds. */
private final long allocationUnits;

/** How much of the root allocation (1.0) this allocation accounts for. */
private final double fractionOfRoot;

private Allocation(String description, long allocationUnits, @Nullable Allocation parent) {
this.description = description;
this.allocationUnits = allocationUnits;
this.parent = parent;

this.fractionOfRoot = parent == null ? 1.0 : parent.fractionOfRoot / parent.allocationUnits;
}

/**
* Creates a new child {@link Allocation} (sub-allocation).
*
* @param description user-facing description of what the sub-allocation represents
* @param allocationUnits number of allocation units the child holds
* @return a new {@link Allocation}
*/
Allocation newChild(String description, long allocationUnits) {
return new Allocation(description, allocationUnits, this);
}

Optional<Allocation> getParent() {
return Optional.ofNullable(parent);
}

String getDescription() {
return description;
}

long getAllocationUnits() {
return allocationUnits;
}

double getFractionOfRoot() {
return fractionOfRoot;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*
* Copyright 2018 Google LLC.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/

package com.google.cloud.tools.jib.event.progress;

import org.junit.Assert;
import org.junit.Test;

/** Tests for {@link Allocation}. */
public class AllocationTest {

/** Error margin for checking equality of two doubles. */
private static final double DOUBLE_ERROR_MARGIN = 1e-10;

@Test
public void testSmoke_linear() {
Allocation root = Allocation.newRoot("root", 1);
Allocation node1 = root.newChild("node1", 2);
Allocation node2 = node1.newChild("node2", 3);

Assert.assertEquals("node2", node2.getDescription());
Assert.assertEquals(3, node2.getAllocationUnits());
Assert.assertEquals(1.0 / 2, node2.getFractionOfRoot(), DOUBLE_ERROR_MARGIN);
Assert.assertTrue(node2.getParent().isPresent());
Assert.assertEquals(node1, node2.getParent().get());

Assert.assertEquals("node1", node1.getDescription());
Assert.assertEquals(2, node1.getAllocationUnits());
Assert.assertTrue(node1.getParent().isPresent());
Assert.assertEquals(root, node1.getParent().get());
Assert.assertEquals(1.0, node1.getFractionOfRoot(), DOUBLE_ERROR_MARGIN);

Assert.assertEquals("root", root.getDescription());
Assert.assertEquals(1, root.getAllocationUnits());
Assert.assertFalse(root.getParent().isPresent());
Assert.assertEquals(1.0, root.getFractionOfRoot(), DOUBLE_ERROR_MARGIN);
}

@Test
public void testFractionOfRoot_tree_partial() {
Allocation root = Allocation.newRoot("ignored", 10);
Allocation left = root.newChild("ignored", 2);
Allocation right = root.newChild("ignored", 4);
Allocation leftDown = left.newChild("ignored", 20);
Allocation rightLeft = right.newChild("ignored", 20);
Allocation rightRight = right.newChild("ignored", 100);
Allocation rightRightDown = rightRight.newChild("ignored", 200);

Assert.assertEquals(1.0, root.getFractionOfRoot(), DOUBLE_ERROR_MARGIN);
Assert.assertEquals(1.0 / 10, left.getFractionOfRoot(), DOUBLE_ERROR_MARGIN);
Assert.assertEquals(1.0 / 10, right.getFractionOfRoot(), DOUBLE_ERROR_MARGIN);
Assert.assertEquals(1.0 / 10 / 2, leftDown.getFractionOfRoot(), DOUBLE_ERROR_MARGIN);
Assert.assertEquals(1.0 / 10 / 4, rightLeft.getFractionOfRoot(), DOUBLE_ERROR_MARGIN);
Assert.assertEquals(1.0 / 10 / 4, rightRight.getFractionOfRoot(), DOUBLE_ERROR_MARGIN);
Assert.assertEquals(
1.0 / 10 / 4 / 100, rightRightDown.getFractionOfRoot(), DOUBLE_ERROR_MARGIN);
}

@Test
public void testFractionOfRoot_tree_complete() {
Allocation root = Allocation.newRoot("ignored", 2);

Allocation left = root.newChild("ignored", 3);
Allocation leftLeft = left.newChild("ignored", 1);
Allocation leftLeftDown = leftLeft.newChild("ignored", 100);
Allocation leftMiddle = left.newChild("ignored", 100);
Allocation leftRight = left.newChild("ignored", 100);

Allocation right = root.newChild("ignored", 1);
Allocation rightDown = right.newChild("ignored", 100);

// Checks that the leaf allocations add up to a full 1.0.
double total =
leftLeftDown.getFractionOfRoot()
+ leftMiddle.getFractionOfRoot()
+ leftRight.getFractionOfRoot()
+ rightDown.getFractionOfRoot();
Assert.assertEquals(1.0, total, DOUBLE_ERROR_MARGIN);
}
}

0 comments on commit af93240

Please sign in to comment.