YARN-5586. Update the Resources class to consider all resource types. Contributed by Varun Vasudev.

This commit is contained in:
Rohith Sharma K S 2016-09-12 10:44:26 +05:30 committed by Wangda Tan
parent 9e4ba6aff5
commit 239c1824a0
7 changed files with 366 additions and 88 deletions

View File

@ -170,7 +170,9 @@ public class ResourcePBImpl extends Resource {
resourceInformation.setName(resource);
}
initResources();
resources.put(resource, resourceInformation);
if (resources.containsKey(resource)) {
resources.put(resource, resourceInformation);
}
}
@Override

View File

@ -183,8 +183,10 @@ public class DominantResourceCalculator extends ResourceCalculator {
Long requiredResourceValue = UnitsConversionUtil
.convert(requiredResource.getUnits(), availableResource.getUnits(),
requiredResource.getValue());
Long tmp = availableResource.getValue() / requiredResourceValue;
min = min < tmp ? min : tmp;
if (requiredResourceValue != 0) {
Long tmp = availableResource.getValue() / requiredResourceValue;
min = min < tmp ? min : tmp;
}
} catch (YarnException ye) {
throw new IllegalArgumentException(
"Error getting resource information for " + resource, ye);
@ -301,10 +303,11 @@ public class DominantResourceCalculator extends ResourceCalculator {
.convert(stepFactorResourceInformation.getUnits(),
rResourceInformation.getUnits(),
stepFactorResourceInformation.getValue());
tmp.setValue(
Math.min(roundUp(Math.max(rValue, minimumValue), stepFactorValue),
maximumValue));
Long value = Math.max(rValue, minimumValue);
if (stepFactorValue != 0) {
value = roundUp(value, stepFactorValue);
}
tmp.setValue(Math.min(value, maximumValue));
ret.setResourceInformation(resource, tmp);
} catch (YarnException ye) {
throw new IllegalArgumentException(
@ -340,9 +343,11 @@ public class DominantResourceCalculator extends ResourceCalculator {
.convert(stepFactorResourceInformation.getUnits(),
rResourceInformation.getUnits(),
stepFactorResourceInformation.getValue());
Long value = roundUp ? roundUp(rValue, stepFactorValue) :
roundDown(rValue, stepFactorValue);
Long value = rValue;
if (stepFactorValue != 0) {
value = roundUp ? roundUp(rValue, stepFactorValue) :
roundDown(rValue, stepFactorValue);
}
tmp.setValue(value);
ret.setResourceInformation(resource, tmp);
} catch (YarnException ye) {
@ -382,10 +387,15 @@ public class DominantResourceCalculator extends ResourceCalculator {
.convert(stepFactorResourceInformation.getUnits(),
rResourceInformation.getUnits(),
stepFactorResourceInformation.getValue());
Long value =
roundUp ? roundUp((long) Math.ceil(rValue * by), stepFactorValue) :
roundDown((long) (rValue * by), stepFactorValue);
Long value;
if (stepFactorValue != 0) {
value = roundUp ?
roundUp((long) Math.ceil(rValue * by), stepFactorValue) :
roundDown((long) (rValue * by), stepFactorValue);
} else {
value =
roundUp ? (long) Math.ceil(rValue * by) : (long) (rValue * by);
}
tmp.setValue(value);
ret.setResourceInformation(resource, tmp);
} catch (YarnException ye) {

View File

@ -241,7 +241,7 @@ public class ResourceUtils {
lock = null;
}
private static String getUnits(String resourceValue) {
public static String getUnits(String resourceValue) {
String units;
for (int i = 0; i < resourceValue.length(); i++) {
if (Character.isAlphabetic(resourceValue.charAt(i))) {
@ -325,4 +325,5 @@ public class ResourceUtils {
synchronized public static void resetNodeResources() {
nodeLock = null;
}
}

View File

@ -25,6 +25,7 @@ import org.apache.hadoop.yarn.api.records.ResourceInformation;
import org.apache.hadoop.yarn.exceptions.ResourceNotFoundException;
import org.apache.hadoop.yarn.exceptions.YarnException;
import org.apache.hadoop.yarn.util.Records;
import org.apache.hadoop.yarn.util.UnitsConversionUtil;
import java.util.Collections;
import java.util.HashMap;
@ -142,6 +143,11 @@ public class Resources {
tmp.get(entry.getKey()).setValue(resourceValue);
}
}
// this is a fix for getVirtualCores returning an int
if (resourceValue > Integer.MAX_VALUE) {
tmp.get(ResourceInformation.VCORES.getName())
.setValue((long) Integer.MAX_VALUE);
}
return tmp;
}
@ -187,12 +193,30 @@ public class Resources {
}
public static Resource clone(Resource res) {
return createResource(res.getMemorySize(), res.getVirtualCores());
Resource ret = Resource.newInstance(0, 0);
for (Map.Entry<String, ResourceInformation> entry : res.getResources()
.entrySet()) {
ret.setResourceInformation(entry.getKey(),
ResourceInformation.newInstance(entry.getValue()));
}
return ret;
}
public static Resource addTo(Resource lhs, Resource rhs) {
lhs.setMemorySize(lhs.getMemorySize() + rhs.getMemorySize());
lhs.setVirtualCores(lhs.getVirtualCores() + rhs.getVirtualCores());
for (Map.Entry<String, ResourceInformation> entry : lhs.getResources()
.entrySet()) {
String name = entry.getKey();
try {
ResourceInformation rhsValue = rhs.getResourceInformation(name);
ResourceInformation lhsValue = entry.getValue();
Long convertedRhs = UnitsConversionUtil
.convert(rhsValue.getUnits(), lhsValue.getUnits(),
rhsValue.getValue());
lhs.setResourceValue(name, lhsValue.getValue() + convertedRhs);
} catch (YarnException ye) {
continue;
}
}
return lhs;
}
@ -201,8 +225,20 @@ public class Resources {
}
public static Resource subtractFrom(Resource lhs, Resource rhs) {
lhs.setMemorySize(lhs.getMemorySize() - rhs.getMemorySize());
lhs.setVirtualCores(lhs.getVirtualCores() - rhs.getVirtualCores());
for (Map.Entry<String, ResourceInformation> entry : lhs.getResources()
.entrySet()) {
String name = entry.getKey();
try {
ResourceInformation rhsValue = rhs.getResourceInformation(name);
ResourceInformation lhsValue = entry.getValue();
Long convertedRhs = UnitsConversionUtil
.convert(rhsValue.getUnits(), lhsValue.getUnits(),
rhsValue.getValue());
lhs.setResourceValue(name, lhsValue.getValue() - convertedRhs);
} catch (YarnException ye) {
continue;
}
}
return lhs;
}
@ -233,8 +269,12 @@ public class Resources {
}
public static Resource multiplyTo(Resource lhs, double by) {
lhs.setMemorySize((long)(lhs.getMemorySize() * by));
lhs.setVirtualCores((int)(lhs.getVirtualCores() * by));
for (Map.Entry<String, ResourceInformation> entry : lhs.getResources()
.entrySet()) {
String name = entry.getKey();
ResourceInformation lhsValue = entry.getValue();
lhs.setResourceValue(name, (long) (lhsValue.getValue() * by));
}
return lhs;
}
@ -248,9 +288,20 @@ public class Resources {
*/
public static Resource multiplyAndAddTo(
Resource lhs, Resource rhs, double by) {
lhs.setMemorySize(lhs.getMemorySize() + (long)(rhs.getMemorySize() * by));
lhs.setVirtualCores(lhs.getVirtualCores()
+ (int)(rhs.getVirtualCores() * by));
for (Map.Entry<String, ResourceInformation> entry : lhs.getResources()
.entrySet()) {
String name = entry.getKey();
try {
ResourceInformation rhsValue = rhs.getResourceInformation(name);
ResourceInformation lhsValue = entry.getValue();
Long convertedRhs = (long) (UnitsConversionUtil
.convert(rhsValue.getUnits(), lhsValue.getUnits(),
rhsValue.getValue()) * by);
lhs.setResourceValue(name, lhsValue.getValue() + convertedRhs);
} catch (YarnException ye) {
continue;
}
}
return lhs;
}
@ -266,8 +317,12 @@ public class Resources {
public static Resource multiplyAndRoundDown(Resource lhs, double by) {
Resource out = clone(lhs);
out.setMemorySize((long)(lhs.getMemorySize() * by));
out.setVirtualCores((int)(lhs.getVirtualCores() * by));
for (Map.Entry<String, ResourceInformation> entry : out.getResources()
.entrySet()) {
String name = entry.getKey();
ResourceInformation lhsValue = entry.getValue();
out.setResourceValue(name, (long) (lhsValue.getValue() * by));
}
return out;
}
@ -367,8 +422,23 @@ public class Resources {
}
public static boolean fitsIn(Resource smaller, Resource bigger) {
return smaller.getMemorySize() <= bigger.getMemorySize() &&
smaller.getVirtualCores() <= bigger.getVirtualCores();
for (Map.Entry<String, ResourceInformation> entry : smaller.getResources()
.entrySet()) {
String name = entry.getKey();
try {
ResourceInformation rhsValue = bigger.getResourceInformation(name);
ResourceInformation lhsValue = entry.getValue();
Long convertedRhs = UnitsConversionUtil
.convert(rhsValue.getUnits(), lhsValue.getUnits(),
rhsValue.getValue());
if(lhsValue.getValue() > convertedRhs) {
return false;
}
} catch (YarnException ye) {
return false;
}
}
return true;
}
public static boolean fitsIn(ResourceCalculator rc, Resource cluster,
@ -377,13 +447,45 @@ public class Resources {
}
public static Resource componentwiseMin(Resource lhs, Resource rhs) {
return createResource(Math.min(lhs.getMemorySize(), rhs.getMemorySize()),
Math.min(lhs.getVirtualCores(), rhs.getVirtualCores()));
Resource ret = createResource(0);
for (Map.Entry<String, ResourceInformation> entry : lhs.getResources()
.entrySet()) {
String name = entry.getKey();
try {
ResourceInformation rhsValue = rhs.getResourceInformation(name);
ResourceInformation lhsValue = entry.getValue();
Long convertedRhs = UnitsConversionUtil
.convert(rhsValue.getUnits(), lhsValue.getUnits(),
rhsValue.getValue());
ResourceInformation outInfo =
lhsValue.getValue() < convertedRhs ? lhsValue : rhsValue;
ret.setResourceInformation(name, outInfo);
} catch (YarnException ye) {
continue;
}
}
return ret;
}
public static Resource componentwiseMax(Resource lhs, Resource rhs) {
return createResource(Math.max(lhs.getMemorySize(), rhs.getMemorySize()),
Math.max(lhs.getVirtualCores(), rhs.getVirtualCores()));
Resource ret = createResource(0);
for (Map.Entry<String, ResourceInformation> entry : lhs.getResources()
.entrySet()) {
String name = entry.getKey();
try {
ResourceInformation rhsValue = rhs.getResourceInformation(name);
ResourceInformation lhsValue = entry.getValue();
Long convertedRhs = UnitsConversionUtil
.convert(rhsValue.getUnits(), lhsValue.getUnits(),
rhsValue.getValue());
ResourceInformation outInfo =
lhsValue.getValue() > convertedRhs ? lhsValue : rhsValue;
ret.setResourceInformation(name, outInfo);
} catch (YarnException ye) {
continue;
}
}
return ret;
}
public static boolean isAnyMajorResourceZero(ResourceCalculator rc,

View File

@ -24,6 +24,7 @@ import org.apache.hadoop.yarn.api.protocolrecords.ResourceTypes;
import org.apache.hadoop.yarn.api.records.Resource;
import org.apache.hadoop.yarn.api.records.ResourceInformation;
import org.apache.hadoop.yarn.conf.YarnConfiguration;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
@ -51,6 +52,17 @@ public class TestResourceUtils {
ResourceUtils.resetResourceTypes();
}
@After
public void teardown() {
Configuration conf = new YarnConfiguration();
File source = new File(
conf.getClassLoader().getResource("resource-types-1.xml").getFile());
File dest = new File(source.getParent(), "resource-types.xml");
if (dest.exists()) {
dest.delete();
}
}
private void testMemoryAndVcores(Map<String, ResourceInformation> res) {
String memory = ResourceInformation.MEMORY_MB.getName();
String vcores = ResourceInformation.VCORES.getName();
@ -251,6 +263,7 @@ public class TestResourceUtils {
Configuration conf = new YarnConfiguration();
Map<String, Resource> testRun = new HashMap<>();
setupResourceTypes(conf, "resource-types-4.xml");
// testRun.put("node-resources-1.xml", Resource.newInstance(1024, 1));
Resource test3Resources = Resource.newInstance(1024, 1);
test3Resources.setResourceInformation("resource1",
@ -272,4 +285,14 @@ public class TestResourceUtils {
Assert.assertEquals(entry.getValue().getResources(), actual);
}
}
public static String setupResourceTypes(Configuration conf, String filename)
throws Exception {
File source = new File(
conf.getClassLoader().getResource(filename).getFile());
File dest = new File(source.getParent(), "resource-types.xml");
FileUtils.copyFile(source, dest);
ResourceUtils.getResourceTypes();
return dest.getAbsolutePath();
}
}

View File

@ -18,35 +18,93 @@
package org.apache.hadoop.yarn.util.resource;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.yarn.api.records.Resource;
import org.apache.hadoop.yarn.api.records.ResourceInformation;
import org.apache.hadoop.yarn.conf.YarnConfiguration;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.File;
import static org.apache.hadoop.yarn.util.resource.Resources.componentwiseMin;
import static org.apache.hadoop.yarn.util.resource.Resources.componentwiseMax;
import static org.apache.hadoop.yarn.util.resource.Resources.add;
import static org.apache.hadoop.yarn.util.resource.Resources.subtract;
import static org.apache.hadoop.yarn.util.resource.Resources.multiply;
import static org.apache.hadoop.yarn.util.resource.Resources.multiplyAndAddTo;
import static org.apache.hadoop.yarn.util.resource.Resources.multiplyAndRoundDown;
import static org.apache.hadoop.yarn.util.resource.Resources.fitsIn;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class TestResources {
private static final String EXTRA_RESOURCE_TYPE = "resource2";
private String resourceTypesFile;
private void setupExtraResourceType() throws Exception {
Configuration conf = new YarnConfiguration();
resourceTypesFile =
TestResourceUtils.setupResourceTypes(conf, "resource-types-3.xml");
}
private void unsetExtraResourceType() {
deleteResourceTypesFile();
ResourceUtils.resetResourceTypes();
}
private void deleteResourceTypesFile() {
if (resourceTypesFile != null && !resourceTypesFile.isEmpty()) {
File resourceFile = new File(resourceTypesFile);
resourceFile.delete();
}
}
@Before
public void setup() throws Exception {
setupExtraResourceType();
}
@After
public void teardown() {
deleteResourceTypesFile();
}
public Resource createResource(long memory, int vCores) {
return Resource.newInstance(memory, vCores);
}
@Test(timeout=10000)
public Resource createResource(long memory, int vCores, long resource2) {
Resource ret = Resource.newInstance(memory, vCores);
ret.setResourceInformation(EXTRA_RESOURCE_TYPE,
ResourceInformation.newInstance(EXTRA_RESOURCE_TYPE, resource2));
return ret;
}
@Test(timeout = 10000)
public void testCompareToWithUnboundedResource() {
assertTrue(Resources.unbounded().compareTo(
createResource(Long.MAX_VALUE, Integer.MAX_VALUE)) == 0);
assertTrue(Resources.unbounded().compareTo(
createResource(Long.MAX_VALUE, 0)) > 0);
assertTrue(Resources.unbounded().compareTo(
createResource(0, Integer.MAX_VALUE)) > 0);
unsetExtraResourceType();
Resource unboundedClone = Resources.clone(Resources.unbounded());
assertTrue(unboundedClone
.compareTo(createResource(Long.MAX_VALUE, Integer.MAX_VALUE)) == 0);
assertTrue(unboundedClone.compareTo(createResource(Long.MAX_VALUE, 0)) > 0);
assertTrue(
unboundedClone.compareTo(createResource(0, Integer.MAX_VALUE)) > 0);
}
@Test(timeout=10000)
public void testCompareToWithNoneResource() {
assertTrue(Resources.none().compareTo(createResource(0, 0)) == 0);
assertTrue(Resources.none().compareTo(
createResource(1, 0)) < 0);
assertTrue(Resources.none().compareTo(
createResource(0, 1)) < 0);
assertTrue(Resources.none().compareTo(createResource(1, 0)) < 0);
assertTrue(Resources.none().compareTo(createResource(0, 1)) < 0);
assertTrue(Resources.none().compareTo(createResource(0, 0, 0)) == 0);
assertTrue(Resources.none().compareTo(createResource(1, 0, 0)) < 0);
assertTrue(Resources.none().compareTo(createResource(0, 1, 0)) < 0);
assertTrue(Resources.none().compareTo(createResource(0, 0, 1)) < 0);
assertTrue(Resources.none().compareTo(createResource(0, 0, 1)) < 0);
}
@Test(timeout=10000)
@ -69,4 +127,129 @@ public class TestResources {
assertEquals(memoryErrorMsg, result.getMemorySize(), 0);
assertEquals(vcoreErrorMsg, result.getVirtualCores(), 0);
}
@Test(timeout = 1000)
public void testFitsIn() {
assertTrue(fitsIn(createResource(1, 1), createResource(2, 2)));
assertTrue(fitsIn(createResource(2, 2), createResource(2, 2)));
assertFalse(fitsIn(createResource(2, 2), createResource(1, 1)));
assertFalse(fitsIn(createResource(1, 2), createResource(2, 1)));
assertFalse(fitsIn(createResource(2, 1), createResource(1, 2)));
assertTrue(fitsIn(createResource(1, 1, 1), createResource(2, 2, 2)));
assertTrue(fitsIn(createResource(1, 1, 0), createResource(2, 2, 0)));
assertTrue(fitsIn(createResource(1, 1, 1), createResource(2, 2, 2)));
}
@Test(timeout = 1000)
public void testComponentwiseMin() {
assertEquals(createResource(1, 1),
componentwiseMin(createResource(1, 1), createResource(2, 2)));
assertEquals(createResource(1, 1),
componentwiseMin(createResource(2, 2), createResource(1, 1)));
assertEquals(createResource(1, 1),
componentwiseMin(createResource(1, 2), createResource(2, 1)));
assertEquals(createResource(1, 1, 1),
componentwiseMin(createResource(1, 1, 1), createResource(2, 2, 2)));
assertEquals(createResource(1, 1, 0),
componentwiseMin(createResource(2, 2, 2), createResource(1, 1)));
assertEquals(createResource(1, 1, 2),
componentwiseMin(createResource(1, 2, 2), createResource(2, 1, 3)));
}
@Test
public void testComponentwiseMax() {
assertEquals(createResource(2, 2),
componentwiseMax(createResource(1, 1), createResource(2, 2)));
assertEquals(createResource(2, 2),
componentwiseMax(createResource(2, 2), createResource(1, 1)));
assertEquals(createResource(2, 2),
componentwiseMax(createResource(1, 2), createResource(2, 1)));
assertEquals(createResource(2, 2, 2),
componentwiseMax(createResource(1, 1, 1), createResource(2, 2, 2)));
assertEquals(createResource(2, 2, 2),
componentwiseMax(createResource(2, 2, 2), createResource(1, 1)));
assertEquals(createResource(2, 2, 3),
componentwiseMax(createResource(1, 2, 2), createResource(2, 1, 3)));
assertEquals(createResource(2, 2, 1),
componentwiseMax(createResource(2, 2, 0), createResource(2, 1, 1)));
}
@Test
public void testAdd() {
assertEquals(createResource(2, 3),
add(createResource(1, 1), createResource(1, 2)));
assertEquals(createResource(3, 2),
add(createResource(1, 1), createResource(2, 1)));
assertEquals(createResource(2, 2, 0),
add(createResource(1, 1, 0), createResource(1, 1, 0)));
assertEquals(createResource(2, 2, 3),
add(createResource(1, 1, 1), createResource(1, 1, 2)));
}
@Test
public void testSubtract() {
assertEquals(createResource(1, 0),
subtract(createResource(2, 1), createResource(1, 1)));
assertEquals(createResource(0, 1),
subtract(createResource(1, 2), createResource(1, 1)));
assertEquals(createResource(2, 2, 0),
subtract(createResource(3, 3, 0), createResource(1, 1, 0)));
assertEquals(createResource(1, 1, 2),
subtract(createResource(2, 2, 3), createResource(1, 1, 1)));
}
@Test
public void testClone() {
assertEquals(createResource(1, 1), Resources.clone(createResource(1, 1)));
assertEquals(createResource(1, 1, 0),
Resources.clone(createResource(1, 1)));
assertEquals(createResource(1, 1),
Resources.clone(createResource(1, 1, 0)));
assertEquals(createResource(1, 1, 2),
Resources.clone(createResource(1, 1, 2)));
}
@Test
public void testMultiply() {
assertEquals(createResource(4, 2), multiply(createResource(2, 1), 2));
assertEquals(createResource(4, 2, 0), multiply(createResource(2, 1), 2));
assertEquals(createResource(2, 4), multiply(createResource(1, 2), 2));
assertEquals(createResource(2, 4, 0), multiply(createResource(1, 2), 2));
assertEquals(createResource(6, 6, 0), multiply(createResource(3, 3, 0), 2));
assertEquals(createResource(4, 4, 6), multiply(createResource(2, 2, 3), 2));
}
@Test
public void testMultiplyAndRoundDown() {
assertEquals(createResource(4, 1),
multiplyAndRoundDown(createResource(3, 1), 1.5));
assertEquals(createResource(4, 1, 0),
multiplyAndRoundDown(createResource(3, 1), 1.5));
assertEquals(createResource(1, 4),
multiplyAndRoundDown(createResource(1, 3), 1.5));
assertEquals(createResource(1, 4, 0),
multiplyAndRoundDown(createResource(1, 3), 1.5));
assertEquals(createResource(7, 7, 0),
multiplyAndRoundDown(createResource(3, 3, 0), 2.5));
assertEquals(createResource(2, 2, 7),
multiplyAndRoundDown(createResource(1, 1, 3), 2.5));
}
@Test
public void testMultiplyAndAddTo() {
assertEquals(createResource(6, 4),
multiplyAndAddTo(createResource(3, 1), createResource(2, 2), 1.5));
assertEquals(createResource(6, 4, 0),
multiplyAndAddTo(createResource(3, 1), createResource(2, 2), 1.5));
assertEquals(createResource(4, 7),
multiplyAndAddTo(createResource(1, 1), createResource(2, 4), 1.5));
assertEquals(createResource(4, 7, 0),
multiplyAndAddTo(createResource(1, 1), createResource(2, 4), 1.5));
assertEquals(createResource(6, 4, 0),
multiplyAndAddTo(createResource(3, 1, 0), createResource(2, 2, 0),
1.5));
assertEquals(createResource(6, 4, 6),
multiplyAndAddTo(createResource(3, 1, 2), createResource(2, 2, 3),
1.5));
}
}

View File

@ -1,43 +0,0 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.hadoop.yarn.server.resourcemanager.resource;
import static org.apache.hadoop.yarn.util.resource.Resources.*;
import static org.junit.Assert.*;
import org.junit.Test;
public class TestResources {
@Test(timeout=10000)
public void testFitsIn() {
assertTrue(fitsIn(createResource(1, 1), createResource(2, 2)));
assertTrue(fitsIn(createResource(2, 2), createResource(2, 2)));
assertFalse(fitsIn(createResource(2, 2), createResource(1, 1)));
assertFalse(fitsIn(createResource(1, 2), createResource(2, 1)));
assertFalse(fitsIn(createResource(2, 1), createResource(1, 2)));
}
@Test(timeout=10000)
public void testComponentwiseMin() {
assertEquals(createResource(1, 1),
componentwiseMin(createResource(1, 1), createResource(2, 2)));
assertEquals(createResource(1, 1),
componentwiseMin(createResource(2, 2), createResource(1, 1)));
assertEquals(createResource(1, 1),
componentwiseMin(createResource(1, 2), createResource(2, 1)));
}
}