diff --git a/src/share/classes/com/alibaba/rcm/Constraint.java b/src/share/classes/com/alibaba/rcm/Constraint.java index 85dd7a0d14cd1d6faf7904ae1939e9a4bc480f48..94531a6fb153c7814941b538749e93800a938652 100644 --- a/src/share/classes/com/alibaba/rcm/Constraint.java +++ b/src/share/classes/com/alibaba/rcm/Constraint.java @@ -47,8 +47,7 @@ public class Constraint { /** * Constraint should be instantiated by {@link ResourceType#newConstraint(long...)} */ - Constraint(ResourceType type, long[] values) { - assert type.validate(values); + protected Constraint(ResourceType type, long[] values) { this.type = type; this.values = values; } diff --git a/src/share/classes/com/alibaba/rcm/ResourceType.java b/src/share/classes/com/alibaba/rcm/ResourceType.java index e0dc45e7281c0574f8f98fa6dd128e9e1b49f07c..c18239bd4e0709c308fbc5736c6067596adf942c 100644 --- a/src/share/classes/com/alibaba/rcm/ResourceType.java +++ b/src/share/classes/com/alibaba/rcm/ResourceType.java @@ -22,9 +22,6 @@ package com.alibaba.rcm; -import java.util.Arrays; -import java.util.stream.IntStream; - /** * Enumeration of {@link Constraint}'s type. *
@@ -54,27 +51,38 @@ public class ResourceType { * The value ranges from 0 to CPU_COUNT * 100. For example, {@code 150} * means that ResourceContainer can use up to 1.5 CPU cores. */ - public final static ResourceType CPU_PERCENT = - new ResourceType("CPU_PERCENT", newChecker(0, Runtime.getRuntime().availableProcessors() * 100)); + public final static ResourceType CPU_PERCENT = new ResourceType("CPU_PERCENT") { + @Override + protected void validate(long... values) throws IllegalArgumentException { + if (values == null || values.length != 1 + || values[0] < 1 + || values[0] > Runtime.getRuntime().availableProcessors() * 100) { + throw new IllegalArgumentException("Bad CPU_PERCENT constraint: " + values[0]); + } + } + }; + /** * Throttling the max heap usage. *
* param #1: maximum heap size in bytes */ - public final static ResourceType HEAP_RETAINED = - new ResourceType("HEAP_RETAINED", newChecker(0, Runtime.getRuntime().maxMemory())); + public final static ResourceType HEAP_RETAINED = new ResourceType("HEAP_RETAINED") { + @Override + protected void validate(long... values) throws IllegalArgumentException { + if (values == null || values.length != 1 + || values[0] <= 0 + || values[0] > Runtime.getRuntime().maxMemory()) { + throw new IllegalArgumentException("Bad HEAP_RETAINED constraint: " + values[0]); + } + } + }; + // name of this ResourceType private final String name; - private final ParameterChecker[] checkers; protected ResourceType(String name) { this.name = name; - this.checkers = null; - } - - protected ResourceType(String name, ParameterChecker... checkers) { - this.name = name; - this.checkers = checkers; } /** @@ -85,11 +93,8 @@ public class ResourceType { * @return newly-created Constraint * @throws IllegalArgumentException when parameter check fails */ - public final Constraint newConstraint(long... values) { - if (!validate(values)) { - throw new IllegalArgumentException(this + - " values: " + Arrays.toString(values)); - } + public Constraint newConstraint(long... values) { + validate(values); return new Constraint(this, values); } @@ -102,49 +107,21 @@ public class ResourceType { *
* public final static ResourceType MY_RESOURCE = * new ResourceType() { - * protected boolean validate(long[] values) { + * protected void validate(long[] values) throws IllegalArgumentException { * // the check logic * } * }; ** * @param values parameter value - * @return if parameter is validated + * @throws IllegalArgumentException if validation failed */ - protected boolean validate(long[] values) { - if (checkers == null) { - return true; - } - if (checkers.length != values.length) { - return false; - } - return IntStream.range(0, values.length) - .allMatch(i -> checkers[i].check(values[i])); + protected void validate(long... values) throws IllegalArgumentException { + // No check at all! } @Override public String toString() { - return name; - } - - protected static ParameterChecker newChecker(long from, long to) { - return new ParameterChecker(from, to); - } - - /** - * Helper class for parameter range check. - */ - protected static class ParameterChecker { - private final long from; - private final long to; - - protected ParameterChecker(long from, long to) { - this.from = from; - this.to = to; - } - - protected boolean check(long value) { - return value >= from && value < to; - } + return "ResourceType-" + name; } } diff --git a/src/share/classes/com/alibaba/tenant/NativeDispatcher.java b/src/share/classes/com/alibaba/tenant/NativeDispatcher.java index e09f4bcb6b32c78456a5b458a2bef425cc8a76f7..5fa50373eb398d5c3435f0985442785f25fa9fa5 100644 --- a/src/share/classes/com/alibaba/tenant/NativeDispatcher.java +++ b/src/share/classes/com/alibaba/tenant/NativeDispatcher.java @@ -32,9 +32,22 @@ class NativeDispatcher { // Attach the current thread to given {@code tenant} native void attach(TenantContainer tenant); + // Create and initialize native allocation context + native void createTenantAllocationContext(TenantContainer tenant, long heapLimit); + + // Destroy native allocation context + // NOTE: cannot be called directly in finalize() otherwise will lead to hang issue + native void destroyTenantAllocationContext(long allocationContext); + + // Get memory size currently occupied by this allocation context + native long getTenantOccupiedMemory(long allocationContext); + // Gets an array containing the amount of memory allocated on the Java heap for a set of threads (in bytes) native void getThreadsAllocatedMemory(long[] ids, long[] memSizes); + // Gets the TenantContainer object whose memory space contains
obj
, or null if ROOT tenant container
+ native TenantContainer containerOf(Object obj);
+
private static native void registerNatives0();
static {
@@ -47,4 +60,4 @@ class NativeDispatcher {
});
registerNatives0();
}
-}
\ No newline at end of file
+}
diff --git a/src/share/classes/com/alibaba/tenant/TenantConfiguration.java b/src/share/classes/com/alibaba/tenant/TenantConfiguration.java
index 71179370729e0c04128573ccc92257ad0730ae54..5992f1b8941dabc712b4f0ea8a2bee5f99d65542 100644
--- a/src/share/classes/com/alibaba/tenant/TenantConfiguration.java
+++ b/src/share/classes/com/alibaba/tenant/TenantConfiguration.java
@@ -30,6 +30,7 @@ import java.util.Map;
import java.util.Collection;
import com.alibaba.rcm.ResourceType;
import com.alibaba.rcm.Constraint;
+import static com.alibaba.rcm.ResourceType.*;
/**
*
@@ -70,4 +71,24 @@ public class TenantConfiguration {
void setConstraint(Constraint constraint) {
constraints.put(constraint.getResourceType(), constraint);
}
+
+ /**
+ * Limit total heap size of new {@code TenantContainer} created from this configuration
+ * @param maxJavaHeapBytes maximum heap size in byte
+ * @return current {@code TenantConfiguration}
+ */
+ public TenantConfiguration limitHeap(long maxJavaHeapBytes) {
+ constraints.put(HEAP_RETAINED, HEAP_RETAINED.newConstraint(maxJavaHeapBytes));
+ return this;
+ }
+
+ /**
+ * @return the max amount of heap the tenant is allowed to consume.
+ */
+ public long getMaxHeap() {
+ if (constraints.containsKey(HEAP_RETAINED)) {
+ return constraints.get(HEAP_RETAINED).getValues()[0];
+ }
+ return Runtime.getRuntime().maxMemory();
+ }
}
diff --git a/src/share/classes/com/alibaba/tenant/TenantContainer.java b/src/share/classes/com/alibaba/tenant/TenantContainer.java
index a1309eb0c481ccd20def352aa1710b5a3c4e3f7e..4481b0f78d2f5f512c2316fbe75987633ba1fa85 100644
--- a/src/share/classes/com/alibaba/tenant/TenantContainer.java
+++ b/src/share/classes/com/alibaba/tenant/TenantContainer.java
@@ -93,6 +93,11 @@ public class TenantContainer {
*/
private long tenantId;
+ /*
+ * address of native tenant allocation context
+ */
+ private long allocationContext = 0L;
+
/*
* tenant name
*/
@@ -253,6 +258,10 @@ public class TenantContainer {
*
*/
private void cleanUp() {
+ if (TenantGlobals.isHeapIsolationEnabled()) {
+ nd.destroyTenantAllocationContext(allocationContext);
+ }
+
// clear references
spawnedThreads.clear();
attachedThreads.clear();
@@ -274,6 +283,11 @@ public class TenantContainer {
props = new Properties();
props.putAll(System.getProperties());
tenantContainerMap.put(this.tenantId, this);
+
+ // Create allocation context if heap isolation enabled
+ if (TenantGlobals.isHeapIsolationEnabled()) {
+ nd.createTenantAllocationContext(this, configuration.getMaxHeap());
+ }
}
TenantConfiguration getConfiguration() {
@@ -376,6 +390,7 @@ public class TenantContainer {
if (null == configuration) {
throw new IllegalArgumentException("Failed to create tenant, illegal arguments: configuration is null");
}
+
TenantContainer tc = new TenantContainer(parent, name, configuration);
tenantContainerMap.put(tc.getTenantId(), tc);
return tc;
@@ -424,6 +439,18 @@ public class TenantContainer {
return cpuTime;
}
+ /**
+ * Gets the heap space occupied by this tenant
+ * @return heap space occupied by this tenant, 0 if tenant heap isolation is disabled.
+ * @throws IllegalStateException if -XX:+TenantHeapIsolation is not enabled.
+ */
+ public long getOccupiedMemory() {
+ if (!TenantGlobals.isHeapIsolationEnabled()) {
+ throw new IllegalStateException("-XX:+TenantHeapIsolation is not enabled");
+ }
+ return nd.getTenantOccupiedMemory(allocationContext);
+ }
+
/**
* Runs the code in the target tenant container
* @param task the code to run
@@ -564,6 +591,19 @@ public class TenantContainer {
}
}
+ /**
+ * Retrieve the tenant container where obj
is allocated in
+ * @param obj object to be searched
+ * @return TenantContainer object whose memory space contains obj
,
+ * or null if ROOT tenant container
+ */
+ public static TenantContainer containerOf(Object obj) {
+ if (!TenantGlobals.isHeapIsolationEnabled()) {
+ throw new UnsupportedOperationException("containerOf() only works with -XX:+TenantHeapIsolation");
+ }
+ return obj != null ? nd.containerOf(obj) : null;
+ }
+
/**
* Runs {@code Supplier.get} in the root tenant.
* @param supplier target used to call
diff --git a/src/share/javavm/export/jvm.h b/src/share/javavm/export/jvm.h
index 18997baeb1acaff59701a42d17b4c1547bdeb42f..f1a64d966ed7e142352db6191e7a26760eb903e5 100644
--- a/src/share/javavm/export/jvm.h
+++ b/src/share/javavm/export/jvm.h
@@ -365,7 +365,19 @@ JVM_ElasticHeapGetTotalUncommittedBytes(JNIEnv *env, jclass clazz);
* com.alibaba.tenant.TenantContainer
*/
JNIEXPORT void JNICALL
-JVM_AttachToTenant(JNIEnv *env, jobject tenant);
+JVM_AttachToTenant(JNIEnv *env, jobject ignored, jobject tenant);
+
+JNIEXPORT void JNICALL
+JVM_CreateTenantAllocationContext(JNIEnv *env, jobject ignored, jobject tenant, jlong heapLimit);
+
+JNIEXPORT void JNICALL
+JVM_DestroyTenantAllocationContext(JNIEnv *env, jobject ignored, jlong context);
+
+JNIEXPORT jobject JNICALL
+JVM_TenantContainerOf(JNIEnv* env, jclass tenantContainerClass, jobject obj);
+
+JNIEXPORT jlong JNICALL
+JVM_GetTenantOccupiedMemory(JNIEnv *env, jobject ignored, jlong context);
/*
* java.lang.reflect.Array
diff --git a/src/share/native/com/alibaba/tenant/NativeDispatcher.c b/src/share/native/com/alibaba/tenant/NativeDispatcher.c
index ab5208efce7ca151c93274101d4dfd9c277c05d7..c8b79239bc4ab1299b6e287763196fb702f02cb8 100644
--- a/src/share/native/com/alibaba/tenant/NativeDispatcher.c
+++ b/src/share/native/com/alibaba/tenant/NativeDispatcher.c
@@ -12,7 +12,11 @@
static const JmmInterface* jmm_interface = NULL;
static JNINativeMethod methods[] = {
- {"attach", "(" TENANT ")V", (void *)&JVM_AttachToTenant},
+ {"attach", "(" TENANT ")V", (void *)&JVM_AttachToTenant},
+ {"createTenantAllocationContext", "(" TENANT "J)V", (void *)&JVM_CreateTenantAllocationContext},
+ {"destroyTenantAllocationContext", "(J)V", (void *)&JVM_DestroyTenantAllocationContext},
+ {"getTenantOccupiedMemory", "(J)J", (void *)&JVM_GetTenantOccupiedMemory},
+ {"containerOf", "(Ljava/lang/Object;)"TENANT, (void *)&JVM_TenantContainerOf },
};
JNIEXPORT void JNICALL