Projects
Mega:23.09
openjdk-1.8.0
_service:tar_scm:0004-8193710-jcmd-l-and-jps-co...
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File _service:tar_scm:0004-8193710-jcmd-l-and-jps-commands-do-not-list-Java-pro.patch of Package openjdk-1.8.0
Date: Wed, 31 May 2023 03:55:21 +0000 Subject: [PATCH 04/59] 8193710: jcmd -l and jps commands do not list Java processes running in Docker containers Bug url: https://bugs.openjdk.org/browse/JDK-8193710 --- hotspot/src/os/linux/vm/perfMemory_linux.cpp | 102 ++++++-- .../classes/sun/jvmstat/PlatformSupport.java | 114 +++++++++ .../sun/jvmstat/PlatformSupportImpl.java | 227 ++++++++++++++++++ .../protocol/local/LocalVmManager.java | 93 +++---- .../monitor/protocol/local/PerfDataFile.java | 179 ++++++++------ 5 files changed, 582 insertions(+), 133 deletions(-) create mode 100644 jdk/src/share/classes/sun/jvmstat/PlatformSupport.java create mode 100644 jdk/src/share/classes/sun/jvmstat/PlatformSupportImpl.java diff --git a/hotspot/src/os/linux/vm/perfMemory_linux.cpp b/hotspot/src/os/linux/vm/perfMemory_linux.cpp index 8293b7168..b45032edb 100644 --- a/hotspot/src/os/linux/vm/perfMemory_linux.cpp +++ b/hotspot/src/os/linux/vm/perfMemory_linux.cpp @@ -147,11 +147,23 @@ static void save_memory_to_file(char* addr, size_t size) { // return the user specific temporary directory name. // +// If containerized process, get dirname of +// /proc/{vmid}/root/tmp/{PERFDATA_NAME_user} +// otherwise /tmp/{PERFDATA_NAME_user} +// // the caller is expected to free the allocated memory. // -static char* get_user_tmp_dir(const char* user) { +#define TMP_BUFFER_LEN (4+22) +static char* get_user_tmp_dir(const char* user, int vmid, int nspid) { + char buffer[TMP_BUFFER_LEN]; + char* tmpdir = (char *)os::get_temp_directory(); + assert(strlen(tmpdir) == 4, "No longer using /tmp - update buffer size"); + + if (nspid != -1) { + jio_snprintf(buffer, TMP_BUFFER_LEN, "/proc/%d/root%s", vmid, tmpdir); + tmpdir = buffer; + } - const char* tmpdir = os::get_temp_directory(); const char* perfdir = PERFDATA_NAME; size_t nbytes = strlen(tmpdir) + strlen(perfdir) + strlen(user) + 3; char* dirname = NEW_C_HEAP_ARRAY(char, nbytes, mtInternal); @@ -500,7 +512,10 @@ static char* get_user_name(uid_t uid) { // // the caller is expected to free the allocated memory. // -static char* get_user_name_slow(int vmid, TRAPS) { +// If nspid != -1, look in /proc/{vmid}/root/tmp for directories +// containing nspid, otherwise just look for vmid in /tmp +// +static char* get_user_name_slow(int vmid, int nspid, TRAPS) { // short circuit the directory search if the process doesn't even exist. if (kill(vmid, 0) == OS_ERR) { @@ -516,8 +531,19 @@ static char* get_user_name_slow(int vmid, TRAPS) { // directory search char* oldest_user = NULL; time_t oldest_ctime = 0; + char buffer[TMP_BUFFER_LEN]; + int searchpid; + char* tmpdirname = (char *)os::get_temp_directory(); + assert(strlen(tmpdirname) == 4, "No longer using /tmp - update buffer size"); - const char* tmpdirname = os::get_temp_directory(); + if (nspid == -1) { + searchpid = vmid; + } + else { + jio_snprintf(buffer, MAXPATHLEN, "/proc/%d/root%s", vmid, tmpdirname); + tmpdirname = buffer; + searchpid = nspid; + } // open the temp directory DIR* tmpdirp = os::opendir(tmpdirname); @@ -528,7 +554,7 @@ static char* get_user_name_slow(int vmid, TRAPS) { } // for each entry in the directory that matches the pattern hsperfdata_*, - // open the directory and check if the file for the given vmid exists. + // open the directory and check if the file for the given vmid or nspid exists. // The file with the expected name and the latest creation date is used // to determine the user name for the process id. // @@ -571,7 +597,7 @@ static char* get_user_name_slow(int vmid, TRAPS) { errno = 0; while ((udentry = os::readdir(subdirp)) != NULL) { - if (filename_to_pid(udentry->d_name) == vmid) { + if (filename_to_pid(udentry->d_name) == searchpid) { struct stat statbuf; int result; @@ -620,10 +646,51 @@ static char* get_user_name_slow(int vmid, TRAPS) { return(oldest_user); } +// Determine if the vmid is the parent pid +// for a child in a PID namespace. +// return the namespace pid if so, otherwise -1 +static int get_namespace_pid(int vmid) { + char fname[24]; + int retpid = -1; + + snprintf(fname, sizeof(fname), "/proc/%d/status", vmid); + FILE *fp = fopen(fname, "r"); + + if (fp) { + int pid, nspid; + int ret; + while (!feof(fp)) { + ret = fscanf(fp, "NSpid: %d %d", &pid, &nspid); + if (ret == 1) { + break; + } + if (ret == 2) { + retpid = nspid; + break; + } + for (;;) { + int ch = fgetc(fp); + if (ch == EOF || ch == (int)'\n') break; + } + } + fclose(fp); + } + return retpid; +} + // return the name of the user that owns the JVM indicated by the given vmid. // -static char* get_user_name(int vmid, TRAPS) { - return get_user_name_slow(vmid, THREAD); +static char* get_user_name(int vmid, int *nspid, TRAPS) { + char *result = get_user_name_slow(vmid, *nspid, THREAD); + + // If we are examining a container process without PID namespaces enabled + // we need to use /proc/{pid}/root/tmp to find hsperfdata files. + if (result == NULL) { + result = get_user_name_slow(vmid, vmid, THREAD); + // Enable nspid logic going forward + if (result != NULL) *nspid = vmid; + } + return result; } // return the file name of the backing store file for the named @@ -631,13 +698,15 @@ static char* get_user_name(int vmid, TRAPS) { // // the caller is expected to free the allocated memory. // -static char* get_sharedmem_filename(const char* dirname, int vmid) { +static char* get_sharedmem_filename(const char* dirname, int vmid, int nspid) { + + int pid = (nspid == -1) ? vmid : nspid; // add 2 for the file separator and a null terminator. size_t nbytes = strlen(dirname) + UINT_CHARS + 2; char* name = NEW_C_HEAP_ARRAY(char, nbytes, mtInternal); - snprintf(name, nbytes, "%s/%d", dirname, vmid); + snprintf(name, nbytes, "%s/%d", dirname, pid); return name; } @@ -929,8 +998,8 @@ static char* mmap_create_shared(size_t size) { if (user_name == NULL) return NULL; - char* dirname = get_user_tmp_dir(user_name); - char* filename = get_sharedmem_filename(dirname, vmid); + char* dirname = get_user_tmp_dir(user_name, vmid, -1); + char* filename = get_sharedmem_filename(dirname, vmid, -1); // get the short filename char* short_filename = strrchr(filename, '/'); if (short_filename == NULL) { @@ -1076,8 +1145,11 @@ static void mmap_attach_shared(const char* user, int vmid, PerfMemory::PerfMemor "Illegal access mode"); } + // determine if vmid is for a containerized process + int nspid = get_namespace_pid(vmid); + if (user == NULL || strlen(user) == 0) { - luser = get_user_name(vmid, CHECK); + luser = get_user_name(vmid, &nspid, CHECK); } else { luser = user; @@ -1088,7 +1160,7 @@ static void mmap_attach_shared(const char* user, int vmid, PerfMemory::PerfMemor "Could not map vmid to user Name"); } - char* dirname = get_user_tmp_dir(luser); + char* dirname = get_user_tmp_dir(luser, vmid, nspid); // since we don't follow symbolic links when creating the backing // store file, we don't follow them when attaching either. @@ -1099,7 +1171,7 @@ static void mmap_attach_shared(const char* user, int vmid, PerfMemory::PerfMemor "Process not found"); } - char* filename = get_sharedmem_filename(dirname, vmid); + char* filename = get_sharedmem_filename(dirname, vmid, nspid); // copy heap memory to resource memory. the open_sharedmem_file // method below need to use the filename, but could throw an diff --git a/jdk/src/share/classes/sun/jvmstat/PlatformSupport.java b/jdk/src/share/classes/sun/jvmstat/PlatformSupport.java new file mode 100644 index 000000000..84f3b2274 --- /dev/null +++ b/jdk/src/share/classes/sun/jvmstat/PlatformSupport.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. 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. Oracle 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. + * + * 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. + */ +package sun.jvmstat; + +import java.io.File; +import java.lang.reflect.Constructor; +import java.util.Collections; +import java.util.List; +import sun.misc.VMSupport; + +/* + * Support routines handling temp directory locating + * and process ID extraction. + */ +public class PlatformSupport { + private static final String tmpDirName; + static { + /* + * For this to work, the target VM and this code need to use + * the same directory. Instead of guessing which directory the + * VM is using, we will ask. + */ + String tmpdir = VMSupport.getVMTemporaryDirectory(); + + /* + * Assure that the string returned has a trailing File.separator + * character. This check was added because the Linux implementation + * changed such that the java.io.tmpdir string no longer terminates + * with a File.separator character. + */ + if (tmpdir.lastIndexOf(File.separator) != (tmpdir.length()-1)) { + tmpdir = tmpdir + File.separator; + } + tmpDirName = tmpdir; + } + + public static PlatformSupport getInstance() { + try { + Class<?> c = Class.forName("sun.jvmstat.PlatformSupportImpl"); + @SuppressWarnings("unchecked") + Constructor<PlatformSupport> cntr = (Constructor<PlatformSupport>) c.getConstructor(); + return cntr.newInstance(); + } catch (ClassNotFoundException e) { + return new PlatformSupport(); + } catch (ReflectiveOperationException e) { + throw new InternalError(e); + } + } + + // package-private + PlatformSupport() {} + + /* + * Return the OS specific temporary directory + */ + public static String getTemporaryDirectory() { + return tmpDirName; + } + + /* + * Return a list of the temporary directories that the VM uses + * for the attach and perf data files. This function returns + * the traditional temp directory in addition to any paths + * accessible by the host which map to temp directories used + * by containers. The container functionality is only currently + * supported on Linux platforms. + * + * It is important that this directory is well-known and the + * same for all VM instances. It cannot be affected by configuration + * variables such as java.io.tmpdir. + */ + public List<String> getTemporaryDirectories(int vmid) { + // Add the default temporary directory only + return Collections.singletonList(tmpDirName); + } + + /* + * Extract the host PID from a file path. + */ + public int getLocalVmId(File file) throws NumberFormatException { + return Integer.parseInt(file.getName()); + } + + + /* + * Return the inner most namespaced PID if there is one, + * otherwise return the original PID. + */ + public int getNamespaceVmId(int pid) { + return pid; + } +} diff --git a/jdk/src/share/classes/sun/jvmstat/PlatformSupportImpl.java b/jdk/src/share/classes/sun/jvmstat/PlatformSupportImpl.java new file mode 100644 index 000000000..4d1d718ab --- /dev/null +++ b/jdk/src/share/classes/sun/jvmstat/PlatformSupportImpl.java @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. 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. Oracle 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. + * + * 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. + */ + +package sun.jvmstat; + +import java.io.*; +import java.util.*; +import java.util.regex.*; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.Files; +import java.nio.charset.*; + +/* + * Linux specific implementation of the PlatformSupport routines + * providing process ID and temp directory support for host and + * cgroup container processes. + */ +public class PlatformSupportImpl extends PlatformSupport { + private static final String containerTmpPath = "/root" + getTemporaryDirectory(); + private static final String pidPatternStr = "^[0-9]+$"; + + /* + * Return the temporary directories that the VM uses for the attach + * and perf data files. This function returns the traditional + * /tmp directory in addition to paths within the /proc file system + * allowing access to container tmp directories such as /proc/{pid}/root/tmp. + * + * It is important that this directory is well-known and the + * same for all VM instances. It cannot be affected by configuration + * variables such as java.io.tmpdir. + * + * Implementation Details: + * + * Java processes that run in docker containers are typically running + * under cgroups with separate pid namespaces which means that pids + * within the container are different that the pid which is visible + * from the host. The container pids typically start with 1 and + * increase. The java process running in the container will use these + * pids when creating the hsperfdata files. In order to locate java + * processes that are running in containers, we take advantage of + * the Linux proc file system which maps the containers tmp directory + * to the hosts under /proc/{hostpid}/root/tmp. We use the /proc status + * file /proc/{hostpid}/status to determine the containers pid and + * then access the hsperfdata file. The status file contains an + * entry "NSPid:" which shows the mapping from the hostpid to the + * containers pid. + * + * Example: + * + * NSPid: 24345 11 + * + * In this example process 24345 is visible from the host, + * is running under the PID namespace and has a container specific + * pid of 11. + * + * The search for Java processes is done by first looking in the + * traditional /tmp for host process hsperfdata files and then + * the search will container in every /proc/{pid}/root/tmp directory. + * There are of course added complications to this search that + * need to be taken into account. + * + * 1. duplication of tmp directories + * + * /proc/{hostpid}/root/tmp directories exist for many processes + * that are running on a Linux kernel that has cgroups enabled even + * if they are not running in a container. To avoid this duplication, + * we compare the inode of the /proc tmp directories to /tmp and + * skip these duplicated directories. + * + * 2. Containerized processes without PID namespaces being enabled. + * + * If a container is running a Java process without namespaces being + * enabled, an hsperfdata file will only be located at + * /proc/{hostpid}/root/tmp/{hostpid}. This is handled by + * checking the last component in the path for both the hostpid + * and potential namespacepids (if one exists). + */ + public List<String> getTemporaryDirectories(int pid) { + FilenameFilter pidFilter; + Matcher pidMatcher; + Pattern pidPattern = Pattern.compile(pidPatternStr); + long tmpInode = 0; + + File procdir = new File("/proc"); + + if (pid != 0) { + pidPattern = Pattern.compile(Integer.toString(pid)); + } + else { + pidPattern = Pattern.compile(pidPatternStr); + } + pidMatcher = pidPattern.matcher(""); + + // Add the default temporary directory first + List<String> v = new ArrayList<>(); + v.add(getTemporaryDirectory()); + + try { + File f = new File(getTemporaryDirectory()); + tmpInode = (Long)Files.getAttribute(f.toPath(), "unix:ino"); + } + catch (IOException e) {} + + pidFilter = new FilenameFilter() { + public boolean accept(File dir, String name) { + if (!dir.isDirectory()) + return false; + pidMatcher.reset(name); + return pidMatcher.matches(); + } + }; + + File[] dirs = procdir.listFiles(pidFilter); + + // Add all unique /proc/{pid}/root/tmp dirs that are not mapped to /tmp + for (File dir : dirs) { + String containerTmpDir = dir.getAbsolutePath() + containerTmpPath; + File containerFile = new File(containerTmpDir); + + try { + long procInode = (Long)Files.getAttribute(containerFile.toPath(), "unix:ino"); + if (containerFile.exists() && containerFile.isDirectory() && + containerFile.canRead() && procInode != tmpInode) { + v.add(containerTmpDir); + } + } + catch (IOException e) {} + } + + return v; + } + + + /* + * Extract either the host PID or the NameSpace PID + * from a file path. + * + * File path should be in 1 of these 2 forms: + * + * /proc/{pid}/root/tmp/hsperfdata_{user}/{nspid} + * or + * /tmp/hsperfdata_{user}/{pid} + * + * In either case we want to return {pid} and NOT {nspid} + * + * This function filters out host pids which do not have + * associated hsperfdata files. This is due to the fact that + * getTemporaryDirectories will return /proc/{pid}/root/tmp + * paths for all container processes whether they are java + * processes or not causing duplicate matches. + */ + public int getLocalVmId(File file) throws NumberFormatException { + String p = file.getAbsolutePath(); + String s[] = p.split("\\/"); + + // Determine if this file is from a container + if (s.length == 7 && s[1].equals("proc")) { + int hostpid = Integer.parseInt(s[2]); + int nspid = Integer.parseInt(s[6]); + if (nspid == hostpid || nspid == getNamespaceVmId(hostpid)) { + return hostpid; + } + else { + return -1; + } + } + else { + return Integer.parseInt(file.getName()); + } + } + + + /* + * Return the inner most namespaced PID if there is one, + * otherwise return the original PID. + */ + public int getNamespaceVmId(int pid) { + // Assuming a real procfs sits beneath, reading this doesn't block + // nor will it consume a lot of memory. + Path statusPath = Paths.get("/proc", Integer.toString(pid), "status"); + if (Files.notExists(statusPath)) { + return pid; // Likely a bad pid, but this is properly handled later. + } + + try { + for (String line : Files.readAllLines(statusPath, StandardCharsets.UTF_8)) { + String[] parts = line.split(":"); + if (parts.length == 2 && parts[0].trim().equals("NSpid")) { + parts = parts[1].trim().split("\\s+"); + // The last entry represents the PID the JVM "thinks" it is. + // Even in non-namespaced pids these entries should be + // valid. You could refer to it as the inner most pid. + int ns_pid = Integer.parseInt(parts[parts.length - 1]); + return ns_pid; + } + } + // Old kernels may not have NSpid field (i.e. 3.10). + // Fallback to original pid in the event we cannot deduce. + return pid; + } catch (NumberFormatException | IOException x) { + return pid; + } + } +} diff --git a/jdk/src/share/classes/sun/jvmstat/perfdata/monitor/protocol/local/LocalVmManager.java b/jdk/src/share/classes/sun/jvmstat/perfdata/monitor/protocol/local/LocalVmManager.java index fde75fb2d..35d25700d 100644 --- a/jdk/src/share/classes/sun/jvmstat/perfdata/monitor/protocol/local/LocalVmManager.java +++ b/jdk/src/share/classes/sun/jvmstat/perfdata/monitor/protocol/local/LocalVmManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2018, Oracle and/or its affiliates. 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 @@ -45,7 +45,7 @@ import java.io.*; */ public class LocalVmManager { private String userName; // user name for monitored jvm - private File tmpdir; + private List<String> tmpdirs; private Pattern userPattern; private Matcher userMatcher; private FilenameFilter userFilter; @@ -77,8 +77,9 @@ public class LocalVmManager { public LocalVmManager(String user) { this.userName = user; + if (userName == null) { - tmpdir = new File(PerfDataFile.getTempDirectory()); + tmpdirs = PerfDataFile.getTempDirectories(null, 0); userPattern = Pattern.compile(PerfDataFile.userDirNamePattern); userMatcher = userPattern.matcher(""); @@ -89,7 +90,7 @@ public class LocalVmManager { } }; } else { - tmpdir = new File(PerfDataFile.getTempDirectory(userName)); + tmpdirs = PerfDataFile.getTempDirectories(userName, 0); } filePattern = Pattern.compile(PerfDataFile.fileNamePattern); @@ -134,65 +135,73 @@ public class LocalVmManager { */ Set<Integer> jvmSet = new HashSet<Integer>(); - if (! tmpdir.isDirectory()) { - return jvmSet; - } + for (String dir : tmpdirs) { + File tmpdir = new File(dir); + if (! tmpdir.isDirectory()) { + continue; + } - if (userName == null) { - /* - * get a list of all of the user temporary directories and - * iterate over the list to find any files within those directories. - */ - File[] dirs = tmpdir.listFiles(userFilter); - - for (int i = 0 ; i < dirs.length; i ++) { - if (!dirs[i].isDirectory()) { - continue; + if (userName == null) { + /* + * get a list of all of the user temporary directories and + * iterate over the list to find any files within those directories. + */ + File[] dirs = tmpdir.listFiles(userFilter); + for (int i = 0 ; i < dirs.length; i ++) { + if (!dirs[i].isDirectory()) { + continue; + } + + // get a list of files from the directory + File[] files = dirs[i].listFiles(fileFilter); + if (files != null) { + for (int j = 0; j < files.length; j++) { + if (files[j].isFile() && files[j].canRead()) { + int vmid = PerfDataFile.getLocalVmId(files[j]); + if (vmid != -1) { + jvmSet.add(vmid); + } + } + } + } } + } else { + /* + * Check if the user directory can be accessed. Any of these + * conditions may have asynchronously changed between subsequent + * calls to this method. + */ - // get a list of files from the directory - File[] files = dirs[i].listFiles(fileFilter); + // get the list of files from the specified user directory + File[] files = tmpdir.listFiles(fileFilter); if (files != null) { for (int j = 0; j < files.length; j++) { if (files[j].isFile() && files[j].canRead()) { - jvmSet.add(new Integer( - PerfDataFile.getLocalVmId(files[j]))); + int vmid = PerfDataFile.getLocalVmId(files[j]); + if (vmid != -1) { + jvmSet.add(vmid); + } } } } } - } else { - /* - * Check if the user directory can be accessed. Any of these - * conditions may have asynchronously changed between subsequent - * calls to this method. - */ - // get the list of files from the specified user directory - File[] files = tmpdir.listFiles(fileFilter); + // look for any 1.4.1 files + File[] files = tmpdir.listFiles(tmpFileFilter); if (files != null) { for (int j = 0; j < files.length; j++) { if (files[j].isFile() && files[j].canRead()) { - jvmSet.add(new Integer( - PerfDataFile.getLocalVmId(files[j]))); + int vmid = PerfDataFile.getLocalVmId(files[j]); + if (vmid != -1) { + jvmSet.add(vmid); + } } } } } - // look for any 1.4.1 files - File[] files = tmpdir.listFiles(tmpFileFilter); - if (files != null) { - for (int j = 0; j < files.length; j++) { - if (files[j].isFile() && files[j].canRead()) { - jvmSet.add(new Integer( - PerfDataFile.getLocalVmId(files[j]))); - } - } - } - return jvmSet; } } diff --git a/jdk/src/share/classes/sun/jvmstat/perfdata/monitor/protocol/local/PerfDataFile.java b/jdk/src/share/classes/sun/jvmstat/perfdata/monitor/protocol/local/PerfDataFile.java index 62c64795b..26045ac5e 100644 --- a/jdk/src/share/classes/sun/jvmstat/perfdata/monitor/protocol/local/PerfDataFile.java +++ b/jdk/src/share/classes/sun/jvmstat/perfdata/monitor/protocol/local/PerfDataFile.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2018 Oracle and/or its affiliates. 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 @@ -26,7 +26,11 @@ package sun.jvmstat.perfdata.monitor.protocol.local; import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; import java.io.FilenameFilter; +import sun.jvmstat.PlatformSupport; /** * Class to provide translations from the local Vm Identifier @@ -44,11 +48,6 @@ import java.io.FilenameFilter; public class PerfDataFile { private PerfDataFile() { }; - /** - * The name of the of the system dependent temporary directory - */ - public static final String tmpDirName; - /** * The file name prefix for PerfData shared memory files. * <p> @@ -79,6 +78,12 @@ public class PerfDataFile { "^hsperfdata_[0-9]+(_[1-2]+)?$"; + /** + * Platform Specific methods for looking up temporary directories + * and process IDs. + */ + private static final PlatformSupport platSupport = PlatformSupport.getInstance(); + /** * Get a File object for the instrumentation backing store file * for the JVM identified by the given local Vm Identifier. @@ -93,7 +98,7 @@ public class PerfDataFile { * @return File - a File object to the backing store file for the named * shared memory region of the target JVM. * @see java.io.File - * @see #getTempDirectory() + * @see #getTempDirectories() */ public static File getFile(int lvmid) { if (lvmid == 0) { @@ -106,56 +111,65 @@ public class PerfDataFile { return null; } - /* - * iterate over all files in all directories in tmpDirName that - * match the file name patterns. - */ - File tmpDir = new File(tmpDirName); - String[] files = tmpDir.list(new FilenameFilter() { - public boolean accept(File dir, String name) { - if (!name.startsWith(dirNamePrefix)) { - return false; - } - File candidate = new File(dir, name); - return ((candidate.isDirectory() || candidate.isFile()) - && candidate.canRead()); - } - }); - - long newestTime = 0; + List<String> tmpDirs = getTempDirectories(null, lvmid); File newest = null; - for (int i = 0; i < files.length; i++) { - File f = new File(tmpDirName + files[i]); - File candidate = null; + for (String dir : tmpDirs) { + /* + * iterate over all files in all directories in this tmpDir that + * match the file name patterns. + */ + File tmpDir = new File(dir); + String[] files = tmpDir.list(new FilenameFilter() { + public boolean accept(File dir, String name) { + if (!name.startsWith(dirNamePrefix)) { + return false; + } + File candidate = new File(dir, name); + return ((candidate.isDirectory() || candidate.isFile()) + && candidate.canRead()); + } + }); - if (f.exists() && f.isDirectory()) { - /* - * found a directory matching the name patterns. This - * is a 1.4.2 hsperfdata_<user> directory. Check for - * file named <lvmid> in that directory - */ - String name = Integer.toString(lvmid); - candidate = new File(f.getName(), name); + long newestTime = 0; - } else if (f.exists() && f.isFile()) { - /* - * found a file matching the name patterns. This - * is a 1.4.1 hsperfdata_<lvmid> file. - */ - candidate = f; + for (String file : files) { + File f = new File(dir + file); + File candidate = null; - } else { - // unexpected - let conditional below filter this one out - candidate = f; - } + if (f.exists() && f.isDirectory()) { + /* + * found a directory matching the name patterns. This + * is a 1.4.2 hsperfdata_<user> directory. Check for + * file named <lvmid> in that directory + */ + String name = f.getAbsolutePath() + File.separator + lvmid; + candidate = new File(name); + // Try NameSpace Id if Host Id doesn't exist. + if (!candidate.exists()) { + name = f.getAbsolutePath() + File.separator + + platSupport.getNamespaceVmId(lvmid); + candidate = new File(name); + } + } else if (f.exists() && f.isFile()) { + /* + * found a file matching the name patterns. This + * is a 1.4.1 hsperfdata_<lvmid> file. + */ + candidate = f; - if (candidate.exists() && candidate.isFile() - && candidate.canRead()) { - long modTime = candidate.lastModified(); - if (modTime >= newestTime) { - newestTime = modTime; - newest = candidate; + } else { + // unexpected - let conditional below filter this one out + candidate = f; + } + + if (candidate.exists() && candidate.isFile() + && candidate.canRead()) { + long modTime = candidate.lastModified(); + if (modTime >= newestTime) { + newestTime = modTime; + newest = candidate; + } } } } @@ -176,7 +190,7 @@ public class PerfDataFile { * @return File - a File object to the backing store file for the named * shared memory region of the target JVM. * @see java.io.File - * @see #getTempDirectory() + * @see #getTempDirectories() */ public static File getFile(String user, int lvmid) { if (lvmid == 0) { @@ -190,11 +204,22 @@ public class PerfDataFile { } // first try for 1.4.2 and later JVMs - String basename = getTempDirectory(user) + Integer.toString(lvmid); - File f = new File(basename); + List<String> tmpDirs = getTempDirectories(user, lvmid); + String basename; + File f; - if (f.exists() && f.isFile() && f.canRead()) { - return f; + for (String dir : tmpDirs) { + basename = dir + lvmid; + f = new File(basename); + if (f.exists() && f.isFile() && f.canRead()) { + return f; + } + // Try NameSpace Id if Host Id doesn't exist. + basename = dir + platSupport.getNamespaceVmId(lvmid); + f = new File(basename); + if (f.exists() && f.isFile() && f.canRead()) { + return f; + } } // No hit on 1.4.2 JVMs, try 1.4.1 files @@ -235,7 +260,7 @@ public class PerfDataFile { public static int getLocalVmId(File file) { try { // try 1.4.2 and later format first - return Integer.parseInt(file.getName()); + return(platSupport.getLocalVmId(file)); } catch (NumberFormatException e) { } // now try the 1.4.1 format @@ -266,7 +291,7 @@ public class PerfDataFile { * @return String - the name of the temporary directory. */ public static String getTempDirectory() { - return tmpDirName; + return PlatformSupport.getTemporaryDirectory(); } /** @@ -282,26 +307,28 @@ public class PerfDataFile { * @return String - the name of the temporary directory. */ public static String getTempDirectory(String user) { - return tmpDirName + dirNamePrefix + user + File.separator; + return getTempDirectory() + dirNamePrefix + user + File.separator; } - static { - /* - * For this to work, the target VM and this code need to use - * the same directory. Instead of guessing which directory the - * VM is using, we will ask. - */ - String tmpdir = sun.misc.VMSupport.getVMTemporaryDirectory(); - - /* - * Assure that the string returned has a trailing File.separator - * character. This check was added because the Linux implementation - * changed such that the java.io.tmpdir string no longer terminates - * with a File.separator character. - */ - if (tmpdir.lastIndexOf(File.separator) != (tmpdir.length()-1)) { - tmpdir = tmpdir + File.separator; + /** + * Return the names of the temporary directories being searched for + * HotSpot PerfData backing store files. + * <p> + * This method returns the traditional host temp directory but also + * includes a list of temp directories used by containers. + * + * @return List<String> - A List of temporary directories to search. + */ + public static List<String> getTempDirectories(String userName, int vmid) { + List<String> list = platSupport.getTemporaryDirectories(vmid); + if (userName == null) { + return list; } - tmpDirName = tmpdir; + + List<String> nameList = list.stream() + .map(name -> name + dirNamePrefix + userName + File.separator) + .collect(Collectors.toList()); + + return nameList; } } -- 2.22.0
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.
浙ICP备2022010568号-2