diff --git a/make/CreateJars.gmk b/make/CreateJars.gmk index e11ddc7bb5..f1628154f8 100644 --- a/make/CreateJars.gmk +++ b/make/CreateJars.gmk @@ -559,7 +559,8 @@ EXPORTED_PRIVATE_PKGS = com.oracle.net \ com.oracle.nio \ com.alibaba.jwarmup \ com.alibaba.management \ - com.alibaba.jvm.gc + com.alibaba.jvm.gc \ + com.alibaba.rcm $(IMAGES_OUTPUTDIR)/symbols/_the.symbols: $(IMAGES_OUTPUTDIR)/lib/rt.jar $(RM) -r $(IMAGES_OUTPUTDIR)/symbols/META-INF/sym diff --git a/src/share/classes/com/alibaba/rcm/Constraint.java b/src/share/classes/com/alibaba/rcm/Constraint.java new file mode 100644 index 0000000000..85dd7a0d14 --- /dev/null +++ b/src/share/classes/com/alibaba/rcm/Constraint.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Alibaba designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +package com.alibaba.rcm; + +import java.util.Arrays; + +/** + * A {@code Constraint} is a pair of {@link ResourceType} and {@code values}. + * The constrained resource and specification of parameter values are documented + * in enum constants in {@link ResourceType} + *

+ * A {@code Constraint} must be associated with one {@code ResourceType}, so we + * provide factory method {@link ResourceType#newConstraint(long...)} to implement + * this restriction. For example: + *

+ *   Constraint cpuConstraint = ResourceType.CPU_PERCENT.newConstraint(30);
+ * 
+ *

+ * {@code ResourceContainer} and {@code Constraint} follow the one-to-many relationship. + * {@link ResourceContainer#getConstraints()} can fetch the Constraint associated with + * ResourceContainer. + */ +public class Constraint { + private final ResourceType type; + private final long[] values; + + /** + * Constraint should be instantiated by {@link ResourceType#newConstraint(long...)} + */ + Constraint(ResourceType type, long[] values) { + assert type.validate(values); + this.type = type; + this.values = values; + } + + /** + * Returns the currently restricted resource type. + * + * @return resource type + */ + public ResourceType getResourceType() { + return type; + } + + /** + * Returns the constraint value of ResourceType described by a long[], + * which is documented on the ResourceType enums. + *

+ * The returned value is a copy of the internal storage array to prevent + * modification. + * + * @return constraint values + */ + public long[] getValues() { + return Arrays.copyOf(values, values.length); + } + + @Override + public String toString() { + return "Constraint{" + + "type=" + type + + ", values=" + Arrays.toString(values) + + '}'; + } +} diff --git a/src/share/classes/com/alibaba/rcm/ResourceContainer.java b/src/share/classes/com/alibaba/rcm/ResourceContainer.java new file mode 100644 index 0000000000..d8f639b2f5 --- /dev/null +++ b/src/share/classes/com/alibaba/rcm/ResourceContainer.java @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Alibaba designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +package com.alibaba.rcm; + +import com.alibaba.rcm.internal.AbstractResourceContainer; + +/** + * A {@code ResourceContainer} defines a set of resource {@link Constraint}s + * that limit resource usage by threads. + * Zero or more threads can be attached to one {@code ResourceContainer}. + *

+ * +-------------------------------+  +-----------------------------+
+ * |ResourceContainer              |  |RootContainer                |
+ * |                               |  |                             |
+ * | +---------------+             |  |                             |
+ * | |CPU Constraint |             |  |        +----------+         |
+ * | +---------------+      <------------------+  Thread  |         |
+ * | +---------------+             |  |        +----------+         |
+ * | |Mem Constraint |command.run()|  | container.run(command)      |
+ * | +---------------+      |      |  |                             |
+ * |    |---------------->  v      |  |                             |
+ * |  resources are   command.run()|  |                             |
+ * |  controlled by   returns      |  |           back to root      |
+ * |  constraints            +----------------->  container         |
+ * |                               |  |                             |
+ * |                               |  |                             |
+ * +-------------------------------+  +-----------------------------+
+ * 
+ * The figure above describes the structure and usage of {@code ResourceContainer}. + *

+ * The main Thread is bounded to root container which can be fetched by + * {@link ResourceContainer#root()}. Root Container is the system default + * {@code ResourceContainer} without any resource restrictions. + * Newly created threads are implicitly bounded to {@code ResourceContainer} + * of the parent thread. + *

+ * A Thread can invoke {@link ResourceContainer#run(Runnable command)} to + * attach to the {@code ResourceContainer} and run the {@code command}, + * the resource usage of the thread is controlled by the {@code ResourceContainer}'s + * constraints while running the command. + * When the execution of the command is either finished normally + * or terminated by Exception, the thread will be detached from the container automatically. + *

+ * Components of a {@code ResourceContainer} implementation: + *

+ * + *

+ * {@code ResourceContainer} needs to be created from a set of {@code Constraint}s + *

+ * In most cases, the following idiom should be used: + *

+ *    ResourceContainer resourceContainer = containerFactory.createContainer(
+ *      Arrays.asList(
+ *          CPU_PERCENT.newConstraint(50),
+ *          HEAP_RETAINED.newConstraint(100_000_000)
+ *    ));
+ *
+ *    resourceContainer.run(requestHandler);
+ *
+ *    resourceContainer.destroy();
+ *  
+ * + * @see ResourceContainerFactory + */ +public interface ResourceContainer { + /** + * An enumeration of Container state + */ + enum State { + /** + * Created but not ready for attaching (initializing). + */ + CREATED, + /** + * Ready for attaching. + */ + RUNNING, + /** + * {@link ResourceContainer#destroy()} has been called. + */ + STOPPING, + /** + * Container is destroyed. Further usage is not allowed. + */ + DEAD + } + + /** + * Returns the system-wide "root" Resource container. + *

+ * Root ResourceContainer is a virtual container that indicates + * the default resource container for any thread, which is not attached + * to a ResourceContainer created by users. Root ResourceContainer does + * not have any resource constrains. + *

+ * {@link #run(Runnable)} method of root container is a special + * implementation that detaches from the current container and returns + * to the root container. + * It is very useful in ResourceContainer switch scenario: + *

+     * // Assume we already attach to a non-root resourceContainer1
+     * resourceContainer2.run(command);
+     * // throws exception, because it is illegal to switch between non-root
+     * // ResourceContainers
+     * ResourceContainer.root(() -> resourceContainer2.run(command));
+     * 
+ * + * @return root container + */ + static ResourceContainer root() { + return AbstractResourceContainer.root(); + } + + /** + * Returns the ResourceContainer associated with the current thread. + * For threads that do not attach to any user-created ResourceContainer, + * {@link #root()} is returned. + * + * @return current ResourceContainer + */ + static ResourceContainer current() { + return AbstractResourceContainer.current(); + } + + /** + * Returns the current ResourceContainer state. + * + * @return current state. + */ + ResourceContainer.State getState(); + + /** + * Attach the current thread to the ResourceContainer to run the {@code command}, + * and detach the ResourceContainer when {@code command} is either normally finished + * or terminated by Exception. + *

+ * At the same time, it is not allowed to switch directly between any two + * containers. If the switch is indeed required, the + * {@link #root()} container should be used. + *

+ * This way restricts the container attach/detach mode for the API users, + * but is less error-prone. + * + *

+     *     ResourceContainer resourceContainer = ....
+     *     assert ResourceContainer.current() == ResourceContainer.root();
+     *     resourceContainer.run(() -> {
+     *         assert ResourceContainer.current() == resourceContainer;
+     *     });
+     *     assert ResourceContainer.current() == ResourceContainer.root();
+     * 
+ * + * @param command the target code + */ + void run(Runnable command); + + /** + * Updates {@link Constraint} of this resource container. + *

+ * Constraints with an identical type will + * replace each other according to the calling order. + * + * @param constraint constraints list + * @throws UnsupportedOperationException {@link Constraint#getResourceType()} is not + * supported by the implementation + */ + void updateConstraint(Constraint constraint); + + /** + * Gets container's {@link Constraint}s + * + * @return {@code Constraint}s + */ + Iterable getConstraints(); + + /** + * Destroys this resource container, also kills the attached threads and releases + * resources described in {@link #getConstraints()}. + *

+ * Once this method is called, the state will become {@link State#STOPPING}. + * And the caller thread will be blocked until all the resources have been released. + * Then the container state will become {@link State#DEAD}. + */ + void destroy(); +} diff --git a/src/share/classes/com/alibaba/rcm/ResourceContainerFactory.java b/src/share/classes/com/alibaba/rcm/ResourceContainerFactory.java new file mode 100644 index 0000000000..ceadfbcd6a --- /dev/null +++ b/src/share/classes/com/alibaba/rcm/ResourceContainerFactory.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Alibaba designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +package com.alibaba.rcm; + +/** + * Factory class for {@link ResourceContainer}. + *

+ * Each ResourceContainer implementation needs to provide a public ResourceContainerFactory + * instance to allow users to choose a specific ResourceContainer implementation: + *

+ * ResourceContainerFactory FACTORY_INSTANCE = new ResourceContainerFactory() {
+ *     protected ResourceContainer createContainer(Iterable constraints) {
+ *         return new AbstractResourceContainer() {
+ *             // implement abstract methods
+ *         }
+ *     }
+ * }
+ * 
+ * Then API users can create ResourceContainer by {@code FACTORY_INSTANCE.createContainer(...)} + */ +public interface ResourceContainerFactory { + + /** + * Returns the system-wide default factory for this invocation of + * the Java virtual machine. + * + * @return The system-wide default factory + */ + static ResourceContainerFactory defaultFactory() { + throw new UnsupportedOperationException("NYI"); + } + + /** + * Builds ResourceContainer with constraints. + * + * @param constraints the target {@code Constraint}s + * @return a newly-created ResourceContainer + */ + ResourceContainer createContainer(Iterable constraints); +} diff --git a/src/share/classes/com/alibaba/rcm/ResourceType.java b/src/share/classes/com/alibaba/rcm/ResourceType.java new file mode 100644 index 0000000000..e0dc45e728 --- /dev/null +++ b/src/share/classes/com/alibaba/rcm/ResourceType.java @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Alibaba designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +package com.alibaba.rcm; + +import java.util.Arrays; +import java.util.stream.IntStream; + +/** + * Enumeration of {@link Constraint}'s type. + *

+ * {@code class} is used instead of {@code enum} to provide extensibility. + * Implementation of resource management can define its resource type. + * Below is an example of extension ResourceType: + * + *

+ *     public class MyResourceType extends ResourceType {
+ *         public final static ResourceType CPU_CFS = new MyResourceType();
+ *
+ *         public MyResourceType() {}
+ *     }
+ * 
+ *

+ * CPU_CFS is an instance of {@code ResourceType}, so it can be used wherever + * ResourceType is handled. + *

+ * The descriptions and parameters of each public final static value need to + * be documented in detail. + */ +public class ResourceType { + /** + * Throttling the CPU usage by CPU percentage. + *

+ * param #1: CPU usage measured in a percentage granularity. + * 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)); + /** + * 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())); + + 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; + } + + /** + * Creates a {@link Constraint} with this {@code ResourceType} and + * the given {@code values}. + * + * @param values constraint values + * @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)); + } + return new Constraint(this, values); + } + + /** + * Checks the validity of parameters. Since a long [] is used to + * express the configuration, a length and range check is required. + *

+ * Each ResourceType instance can implement its own {@code validate()} + * method through Override, for example: + *

+     * public final static ResourceType MY_RESOURCE =
+     *     new ResourceType() {
+     *         protected boolean validate(long[] values) {
+     *              // the check logic
+     *         }
+     *     };
+     * 
+ * + * @param values parameter value + * @return if parameter is validated + */ + 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])); + } + + @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; + } + } +} diff --git a/src/share/classes/com/alibaba/rcm/internal/AbstractResourceContainer.java b/src/share/classes/com/alibaba/rcm/internal/AbstractResourceContainer.java new file mode 100644 index 0000000000..abb0039e05 --- /dev/null +++ b/src/share/classes/com/alibaba/rcm/internal/AbstractResourceContainer.java @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Alibaba designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +package com.alibaba.rcm.internal; + +import com.alibaba.rcm.Constraint; +import com.alibaba.rcm.ResourceContainer; +import sun.misc.SharedSecrets; + +import java.util.Collections; + +/** + * A skeletal implementation of {@link ResourceContainer} that practices + * the attach/detach paradigm described in {@link ResourceContainer#run(Runnable)}. + *

+ * Each {@code ResourceContainer} implementation must inherit from this class. + * + * @see ResourceContainer#run(Runnable) + */ + +public abstract class AbstractResourceContainer implements ResourceContainer { + + protected final static AbstractResourceContainer ROOT = new RootContainer(); + + public static AbstractResourceContainer root() { + return ROOT; + } + + public static AbstractResourceContainer current() { + if (!sun.misc.VM.isBooted()) { + return root(); + } + return SharedSecrets.getJavaLangAccess().getResourceContainer(Thread.currentThread()); + } + + @Override + public void run(Runnable command) { + if (getState() != State.RUNNING) { + throw new IllegalStateException("container not running"); + } + ResourceContainer container = current(); + if (container == this) { + command.run(); + return; + } + if (container != root()) { + throw new IllegalStateException("must be in root container " + + "before running into non-root container."); + } + attach(); + try { + command.run(); + } finally { + detach(); + } + } + + /** + * Attach to this resource container. + * Ensure {@link ResourceContainer#current()} as a root container + * before calling this method. + *

+ * The implementation class must call {@code super.attach()} to coordinate + * with {@link ResourceContainer#current()} + */ + protected void attach() { + SharedSecrets.getJavaLangAccess().setResourceContainer(Thread.currentThread(), this); + } + + /** + * Detach from this resource container and return to root container. + *

+ * The implementation class must call {@code super.detach()} to coordinate + * with {@link ResourceContainer#current()} + */ + protected void detach() { + SharedSecrets.getJavaLangAccess().setResourceContainer(Thread.currentThread(), root()); + } + + private static class RootContainer extends AbstractResourceContainer { + @Override + public void run(Runnable command) { + AbstractResourceContainer container = current(); + if (container == root()) { + command.run(); + return; + } + container.detach(); + try { + command.run(); + } finally { + container.attach(); + } + } + + @Override + public ResourceContainer.State getState() { + return ResourceContainer.State.RUNNING; + } + + @Override + protected void attach() { + throw new UnsupportedOperationException("should not reach here"); + } + + @Override + protected void detach() { + throw new UnsupportedOperationException("should not reach here"); + } + + @Override + public void updateConstraint(Constraint constraint) { + throw new UnsupportedOperationException("updateConstraint() is not supported by root container"); + } + + @Override + public Iterable getConstraints() { + return Collections.emptyList(); + } + + @Override + public void destroy() { + throw new UnsupportedOperationException("destroy() is not supported by root container"); + } + } +} diff --git a/src/share/classes/java/lang/System.java b/src/share/classes/java/lang/System.java index b2747fa7a4..7774d4ad8c 100644 --- a/src/share/classes/java/lang/System.java +++ b/src/share/classes/java/lang/System.java @@ -37,12 +37,14 @@ import java.security.AllPermission; import java.nio.channels.Channel; import java.nio.channels.spi.SelectorProvider; +import com.alibaba.rcm.internal.AbstractResourceContainer; import sun.nio.ch.Interruptible; import sun.reflect.CallerSensitive; import sun.reflect.Reflection; import sun.security.util.SecurityConstants; import sun.reflect.annotation.AnnotationType; + /** * The System class contains several useful class fields * and methods. It cannot be instantiated. @@ -1269,6 +1271,16 @@ public Thread newThreadWithAcc(Runnable target, AccessControlContext acc) { public void invokeFinalize(Object o) throws Throwable { o.finalize(); } + + @Override + public void setResourceContainer(Thread thread, AbstractResourceContainer container) { + thread.resourceContainer = container; + } + + @Override + public AbstractResourceContainer getResourceContainer(Thread thread) { + return thread.resourceContainer; + } }); } } diff --git a/src/share/classes/java/lang/Thread.java b/src/share/classes/java/lang/Thread.java index 0cd6778684..01bc46f154 100644 --- a/src/share/classes/java/lang/Thread.java +++ b/src/share/classes/java/lang/Thread.java @@ -36,6 +36,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.locks.LockSupport; +import com.alibaba.rcm.internal.AbstractResourceContainer; import sun.nio.ch.Interruptible; import sun.reflect.CallerSensitive; import sun.reflect.Reflection; @@ -213,6 +214,10 @@ private static synchronized int nextThreadNum() { private volatile int threadStatus = 0; + /** + * The thread attached {@code ResourceContainer} + */ + AbstractResourceContainer resourceContainer; private static synchronized long nextThreadID() { return ++threadSeqNumber; @@ -423,6 +428,10 @@ private void init(ThreadGroup g, Runnable target, String name, /* Set thread ID */ tid = nextThreadID(); + + /* com.alibaba.rcm API */ + this.resourceContainer = parent.resourceContainer != null ? + parent.resourceContainer : AbstractResourceContainer.root(); } /** diff --git a/src/share/classes/sun/misc/JavaLangAccess.java b/src/share/classes/sun/misc/JavaLangAccess.java index 812f88e209..ec55a29e6f 100644 --- a/src/share/classes/sun/misc/JavaLangAccess.java +++ b/src/share/classes/sun/misc/JavaLangAccess.java @@ -30,6 +30,7 @@ import java.security.AccessControlContext; import java.util.Map; +import com.alibaba.rcm.internal.AbstractResourceContainer; import sun.reflect.ConstantPool; import sun.reflect.annotation.AnnotationType; import sun.nio.ch.Interruptible; @@ -132,4 +133,16 @@ public interface JavaLangAccess { * Invokes the finalize method of the given object. */ void invokeFinalize(Object o) throws Throwable; + + /** + * Set the value of {@code thread.resourceContainer} + * + * @param thread target thread to be modified + */ + void setResourceContainer(Thread thread, AbstractResourceContainer container); + + /** + * Get the reference to the thread attached {@code ResourceContainer} + */ + AbstractResourceContainer getResourceContainer(Thread thread); } diff --git a/test/com/alibaba/rcm/TestConfiguration.java b/test/com/alibaba/rcm/TestConfiguration.java new file mode 100644 index 0000000000..b6d4609733 --- /dev/null +++ b/test/com/alibaba/rcm/TestConfiguration.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Alibaba designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +/* + * @test + * @summary Test builder and update constraint + * @library /lib/testlibrary + * @run main TestConfiguration + */ + +import demo.MyResourceContainer; +import demo.MyResourceFactory; +import demo.MyResourceType; + +import java.util.Arrays; +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +import static jdk.testlibrary.Asserts.assertTrue; + +public class TestConfiguration { + public static void main(String[] args) { + + MyResourceContainer mc = (MyResourceContainer) MyResourceFactory.INSTANCE.createContainer(Arrays.asList( + MyResourceType.MY_RESOURCE1.newConstraint(), + MyResourceType.MY_RESOURCE2.newConstraint())); + + + assertTrue(iterator2Stream(mc.operations.iterator()).collect(Collectors.toSet()) + .equals(new HashSet<>(Arrays.asList("update MY_RESOURCE1", "update MY_RESOURCE2")))); + + mc.updateConstraint(MyResourceType.MY_RESOURCE2.newConstraint()); + + assertTrue(iterator2Stream(mc.operations.iterator()).collect(Collectors.toSet()) + .equals(new HashSet<>(Arrays.asList("update MY_RESOURCE1", "update MY_RESOURCE2", "update MY_RESOURCE2")))); + } + + private static Stream iterator2Stream(Iterator iterator) { + return StreamSupport.stream( + Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED), + false); + } +} diff --git a/test/com/alibaba/rcm/TestInherit.java b/test/com/alibaba/rcm/TestInherit.java new file mode 100644 index 0000000000..d4f30c19a1 --- /dev/null +++ b/test/com/alibaba/rcm/TestInherit.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Alibaba designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +/* + * @test + * @summary Test resource container is inherited from parent + * @library /lib/testlibrary + * @run main TestInherit + */ + +import com.alibaba.rcm.ResourceContainer; +import demo.MyResourceFactory; + +import java.util.Collections; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.FutureTask; + +import static jdk.testlibrary.Asserts.assertEQ; + +public class TestInherit { + public static void main(String[] args) { + assertEQ(ResourceContainer.current(), ResourceContainer.root()); + ResourceContainer rc = MyResourceFactory.INSTANCE.createContainer(Collections.emptyList()); + rc.run(() -> { + assertEQ(ResourceContainer.current(), rc); + FutureTask f1 = new FutureTask<>(ResourceContainer::current); + new Thread(f1).start(); + assertEQ(get(f1), rc); + FutureTask f2 = new FutureTask<>(ResourceContainer::current); + ResourceContainer.root().run(() -> new Thread(f2).start()); + assertEQ(get(f2), ResourceContainer.root()); + }); + + // thread is bound to it's parent thread(the thread called Thread::init()) + // not dependent on where Thread::start() called. + FutureTask f3 = new FutureTask<>(ResourceContainer::current); + Thread t3 = new Thread(f3); + // Thread::init is called in root() + rc.run(t3::start); + assertEQ(get(f3), ResourceContainer.root()); + + FutureTask f4 = new FutureTask<>(ResourceContainer::current); + FutureTask newThread = new FutureTask<>(() -> new Thread(f4)); + // Thread::init is called in container + rc.run(newThread); + get(newThread).start(); + assertEQ(get(f4), rc); + } + + private static V get(Future f) { + try { + return f.get(); + } catch (InterruptedException | ExecutionException e) { + throw new InternalError(e); + } + } +} diff --git a/test/com/alibaba/rcm/TestSkeletalAttach.java b/test/com/alibaba/rcm/TestSkeletalAttach.java new file mode 100644 index 0000000000..8ee14cffb7 --- /dev/null +++ b/test/com/alibaba/rcm/TestSkeletalAttach.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Alibaba designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +/* + * @test + * @summary Test skeletal implementation in AbstractResourceContainer + * @library /lib/testlibrary + * @run main TestSkeletalAttach + */ + +import com.alibaba.rcm.ResourceContainer; +import demo.MyResourceContainer; +import demo.MyResourceFactory; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import static jdk.testlibrary.Asserts.assertTrue; + + +public class TestSkeletalAttach { + public static void main(String[] args) { + MyResourceContainer rc = (MyResourceContainer) MyResourceFactory.INSTANCE.createContainer(Collections.emptyList()); + rc.run(() -> { + assertListEQ(Collections.singletonList("attach"), rc.operations); + }); + assertListEQ(Arrays.asList("attach", "detach"), rc.operations); + + rc.operations.clear(); + rc.run(() -> { + rc.run(() -> { + assertListEQ(Collections.singletonList("attach"), rc.operations); + }); + }); + assertListEQ(Arrays.asList("attach", "detach"), rc.operations); + + rc.operations.clear(); + rc.run(() -> { + assertListEQ(Collections.singletonList("attach"), rc.operations); + ResourceContainer.root().run(() -> { + assertListEQ(Arrays.asList("attach", "detach"), rc.operations); + }); + }); + assertTrue(Arrays.asList("attach", "detach", "attach", "detach").equals(rc.operations)); + + rc.operations.clear(); + rc.run(() -> { + assertListEQ(Collections.singletonList("attach"), rc.operations); + ResourceContainer.root().run(() -> { + rc.run(() -> { + assertListEQ(Arrays.asList("attach", "detach", "attach"), rc.operations); + }); + }); + }); + assertTrue(Arrays.asList("attach", "detach", "attach", "detach", "attach", "detach").equals(rc.operations)); + } + + private static void assertListEQ(List lhs, List rhs) { + assertTrue(lhs.equals(rhs), "expect " + lhs + " equals to " + rhs); + } +} diff --git a/test/com/alibaba/rcm/TestState.java b/test/com/alibaba/rcm/TestState.java new file mode 100644 index 0000000000..aa43c521d8 --- /dev/null +++ b/test/com/alibaba/rcm/TestState.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Alibaba designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +/* + * @test + * @summary Test get tenant state + * @library /lib/testlibrary + * @run main TestState + */ + +import com.alibaba.rcm.ResourceContainer; +import demo.MyResourceFactory; + +import java.util.Collections; + +import static jdk.testlibrary.Asserts.*; + + +public class TestState { + public static void main(String[] args) { + ResourceContainer rc = MyResourceFactory.INSTANCE.createContainer(Collections.emptyList()); + assertEQ(rc.getState(), ResourceContainer.State.RUNNING); + rc.destroy(); + assertEQ(rc.getState(), ResourceContainer.State.DEAD); + } +} diff --git a/test/com/alibaba/rcm/TestSwitchBetweenContainers.java b/test/com/alibaba/rcm/TestSwitchBetweenContainers.java new file mode 100644 index 0000000000..7aa31a16bf --- /dev/null +++ b/test/com/alibaba/rcm/TestSwitchBetweenContainers.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Alibaba designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +/* + * @test + * @summary Test switch between containers + * @library /lib/testlibrary + * @run main TestSkeletalAttach + */ + +import com.alibaba.rcm.ResourceContainer; +import demo.MyResourceFactory; + +import java.util.Collections; + +import static jdk.testlibrary.Asserts.*; + + +public class TestSwitchBetweenContainers { + + public static void main(String[] args) { + ResourceContainer rc1 = MyResourceFactory.INSTANCE.createContainer(Collections.emptyList()); + ResourceContainer rc2 = MyResourceFactory.INSTANCE.createContainer(Collections.emptyList()); + + boolean hasIllegalStateException = false; + + try { + rc1.run(() -> { + rc2.run(() -> { + }); + }); + } catch (IllegalStateException e) { + hasIllegalStateException = true; + } + assertTrue(hasIllegalStateException); + rc1.run(() -> { + ResourceContainer.root().run(() -> { + rc2.run(() -> { + }); + }); + }); + } + +} diff --git a/test/com/alibaba/rcm/demo/MyResourceContainer.java b/test/com/alibaba/rcm/demo/MyResourceContainer.java new file mode 100644 index 0000000000..1f7e4ae485 --- /dev/null +++ b/test/com/alibaba/rcm/demo/MyResourceContainer.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Alibaba designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +package demo; + +import com.alibaba.rcm.Constraint; +import com.alibaba.rcm.internal.AbstractResourceContainer; + +import java.util.ArrayList; +import java.util.List; + +public class MyResourceContainer extends AbstractResourceContainer { + + public List operations = new ArrayList<>(); + + private boolean dead; + + @Override + protected void attach() { + super.attach(); + operations.add("attach"); + } + + @Override + protected void detach() { + super.detach(); + operations.add("detach"); + } + + @Override + public State getState() { + return dead ? State.DEAD : State.RUNNING; + } + + @Override + public void updateConstraint(Constraint constraint) { + operations.add("update " + constraint.getResourceType()); + } + + @Override + public Iterable getConstraints() { + return null; + } + + @Override + public void destroy() { + dead = true; + } +} diff --git a/test/com/alibaba/rcm/demo/MyResourceFactory.java b/test/com/alibaba/rcm/demo/MyResourceFactory.java new file mode 100644 index 0000000000..5f9db9c422 --- /dev/null +++ b/test/com/alibaba/rcm/demo/MyResourceFactory.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Alibaba designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +package demo; + +import com.alibaba.rcm.Constraint; +import com.alibaba.rcm.ResourceContainer; +import com.alibaba.rcm.ResourceContainerFactory; + +public class MyResourceFactory implements ResourceContainerFactory { + + public final static ResourceContainerFactory INSTANCE = new MyResourceFactory(); + + private MyResourceFactory() { /*pass*/} + + @Override + public ResourceContainer createContainer(Iterable constraints) { + MyResourceContainer container = new MyResourceContainer(); + for (Constraint constraint : constraints) { + container.updateConstraint(constraint); + } + return container; + } +} diff --git a/test/com/alibaba/rcm/demo/MyResourceType.java b/test/com/alibaba/rcm/demo/MyResourceType.java new file mode 100644 index 0000000000..a7ad4044c0 --- /dev/null +++ b/test/com/alibaba/rcm/demo/MyResourceType.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Alibaba designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +package demo; + +import com.alibaba.rcm.ResourceType; + +public class MyResourceType extends ResourceType { + public final static ResourceType MY_RESOURCE1 = new MyResourceType("MY_RESOURCE1"); + public final static ResourceType MY_RESOURCE2 = new MyResourceType("MY_RESOURCE2"); + + public MyResourceType(String name) { + super(name); + } +}