changeset 14870:dd1d220caeaf

8242480: Negative value may be returned by getFreeSwapSpaceSize() in the docker Reviewed-by: andrew
author sgehwolf
date Fri, 17 Apr 2020 14:48:11 +0800
parents b0b404c86143
children e488620e4191
files src/solaris/classes/sun/management/OperatingSystemImpl.java test/jdk/internal/platform/docker/GetFreeSwapSpaceSize.java test/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java
diffstat 3 files changed, 123 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/src/solaris/classes/sun/management/OperatingSystemImpl.java	Tue Sep 20 12:37:54 2016 +0530
+++ b/src/solaris/classes/sun/management/OperatingSystemImpl.java	Fri Apr 17 14:48:11 2020 +0800
@@ -65,6 +65,12 @@
         if (containerMetrics != null) {
             long memSwapLimit = containerMetrics.getMemoryAndSwapLimit();
             long memLimit = containerMetrics.getMemoryLimit();
+            long deltaLimit = memSwapLimit - memLimit;
+            // Return 0 when memSwapLimit == memLimit, which means no swap space is allowed.
+            // And the same for memSwapLimit < memLimit.
+            if (deltaLimit <= 0) {
+                return 0;
+            }
             if (memSwapLimit >= 0 && memLimit >= 0) {
                 for (int attempt = 0; attempt < MAX_ATTEMPTS_NUMBER; attempt++) {
                     long memSwapUsage = containerMetrics.getMemoryAndSwapUsage();
@@ -73,8 +79,12 @@
                         // We read "memory usage" and "memory and swap usage" not atomically,
                         // and it's possible to get the negative value when subtracting these two.
                         // If this happens just retry the loop for a few iterations.
-                        if ((memSwapUsage - memUsage) >= 0) {
-                            return memSwapLimit - memLimit - (memSwapUsage - memUsage);
+                        long deltaUsage = memSwapUsage - memUsage;
+                        if (deltaUsage >= 0) {
+                            long freeSwap = deltaLimit - deltaUsage;
+                            if (freeSwap >= 0) {
+                                return freeSwap;
+                            }
                         }
                     }
                 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/internal/platform/docker/GetFreeSwapSpaceSize.java	Fri Apr 17 14:48:11 2020 +0800
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2020 THL A29 Limited, a Tencent company. 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.
+ *
+ * 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.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import com.sun.management.OperatingSystemMXBean;
+import java.lang.management.ManagementFactory;
+
+public class GetFreeSwapSpaceSize {
+    public static void main(String[] args) {
+        System.out.println("TestGetFreeSwapSpaceSize");
+        OperatingSystemMXBean osBean = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
+        for (int i = 0; i < 100; i++) {
+            long size = osBean.getFreeSwapSpaceSize();
+            if (size < 0) {
+                System.out.println("Error: getFreeSwapSpaceSize returns " + size);
+                System.exit(-1);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java	Fri Apr 17 14:48:11 2020 +0800
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2020 THL A29 Limited, a Tencent company. 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.
+ *
+ * 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.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8242480
+ * @library /lib
+ * @build GetFreeSwapSpaceSize
+ * @run driver TestGetFreeSwapSpaceSize
+ */
+import jdk.test.lib.containers.docker.Common;
+import jdk.test.lib.containers.docker.DockerRunOptions;
+import jdk.test.lib.containers.docker.DockerTestUtils;
+import jdk.test.lib.process.OutputAnalyzer;
+
+public class TestGetFreeSwapSpaceSize {
+    private static final String imageName = Common.imageName("memory");
+
+    public static void main(String[] args) throws Exception {
+        if (!DockerTestUtils.canTestDocker()) {
+            return;
+        }
+
+        DockerTestUtils.buildJdkDockerImage(imageName, "Dockerfile-BasicTest", "jdk-docker");
+
+        try {
+            testGetFreeSwapSpaceSize(
+                "150M", Integer.toString(((int) Math.pow(2, 20)) * 150),
+                "150M", Integer.toString(0)
+            );
+        } finally {
+            if (!DockerTestUtils.RETAIN_IMAGE_AFTER_TEST) {
+                DockerTestUtils.removeDockerImage(imageName);
+            }
+        }
+    }
+
+    private static void testGetFreeSwapSpaceSize(String memoryAllocation, String expectedMemory,
+            String swapAllocation, String expectedSwap) throws Exception {
+        Common.logNewTestCase("TestGetFreeSwapSpaceSize");
+
+        DockerRunOptions opts = Common.newOpts(imageName, "GetFreeSwapSpaceSize")
+            .addDockerOpts(
+                "--memory", memoryAllocation,
+                "--memory-swap", swapAllocation
+            );
+
+        OutputAnalyzer out = DockerTestUtils.dockerRunJava(opts);
+        out.shouldHaveExitValue(0)
+           .shouldContain("TestGetFreeSwapSpaceSize");
+    }
+}