Skip to content

Commit a1f426a

Browse files
committed
Revert "[GR-46420] Reduce JDK dependencies of cgroup support."
This reverts commit eaacc56, reversing changes made to b4e2248.
1 parent b756c27 commit a1f426a

File tree

7 files changed

+132
-150
lines changed

7 files changed

+132
-150
lines changed

src/java.base/linux/classes/jdk/internal/platform/CgroupInfo.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ public void setCgroupPath(String cgroupPath) {
107107
*
108108
*/
109109
static CgroupInfo fromCgroupsLine(String line) {
110-
String[] tokens = line.split("\t");
110+
String[] tokens = line.split("\\s+");
111111
if (tokens.length != 4) {
112112
return null;
113113
}

src/java.base/linux/classes/jdk/internal/platform/CgroupSubsystemController.java

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,15 @@
2626
package jdk.internal.platform;
2727

2828
import java.io.IOException;
29+
import java.io.UncheckedIOException;
2930
import java.math.BigInteger;
3031
import java.nio.file.Path;
3132
import java.nio.file.Paths;
3233
import java.util.ArrayList;
3334
import java.util.List;
35+
import java.util.Optional;
3436
import java.util.function.Function;
37+
import java.util.stream.Stream;
3538

3639
/**
3740
* Cgroup version agnostic controller logic
@@ -158,18 +161,16 @@ public static double getDoubleValue(CgroupSubsystemController controller, String
158161
public static long getLongEntry(CgroupSubsystemController controller, String param, String entryname, long defaultRetval) {
159162
if (controller == null) return defaultRetval;
160163

161-
try {
162-
long result = defaultRetval;
163-
for (String line : CgroupUtil.readAllLinesPrivileged(Paths.get(controller.path(), param))) {
164-
String[] tokens = line.split(" ");
165-
if (tokens.length == 2 && tokens[0].equals(entryname)) {
166-
result = Long.parseLong(tokens[1]);
167-
break;
168-
}
169-
}
164+
try (Stream<String> lines = CgroupUtil.readFilePrivileged(Paths.get(controller.path(), param))) {
170165

171-
return result;
172-
} catch (IOException e) {
166+
Optional<String> result = lines.map(line -> line.split(" "))
167+
.filter(line -> (line.length == 2 &&
168+
line[0].equals(entryname)))
169+
.map(line -> line[1])
170+
.findFirst();
171+
172+
return result.isPresent() ? Long.parseLong(result.get()) : defaultRetval;
173+
} catch (UncheckedIOException | IOException e) {
173174
return defaultRetval;
174175
}
175176
}

src/java.base/linux/classes/jdk/internal/platform/CgroupSubsystemFactory.java

Lines changed: 46 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
package jdk.internal.platform;
2727

2828
import java.io.IOException;
29+
import java.io.UncheckedIOException;
2930
import java.lang.System.Logger;
3031
import java.lang.System.Logger.Level;
3132
import java.nio.file.Path;
@@ -37,6 +38,9 @@
3738
import java.util.Optional;
3839
import java.util.Objects;
3940
import java.util.function.Consumer;
41+
import java.util.regex.Matcher;
42+
import java.util.regex.Pattern;
43+
import java.util.stream.Stream;
4044

4145
import jdk.internal.platform.cgroupv1.CgroupV1Subsystem;
4246
import jdk.internal.platform.cgroupv2.CgroupV2Subsystem;
@@ -50,11 +54,36 @@ public class CgroupSubsystemFactory {
5054
private static final String MEMORY_CTRL = "memory";
5155
private static final String PIDS_CTRL = "pids";
5256

57+
/*
58+
* From https://www.kernel.org/doc/Documentation/filesystems/proc.txt
59+
*
60+
* 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue
61+
* (1)(2)(3) (4) (5) (6) (7) (8) (9) (10) (11)
62+
*
63+
* (1) mount ID: unique identifier of the mount (may be reused after umount)
64+
* (2) parent ID: ID of parent (or of self for the top of the mount tree)
65+
* (3) major:minor: value of st_dev for files on filesystem
66+
* (4) root: root of the mount within the filesystem
67+
* (5) mount point: mount point relative to the process's root
68+
* (6) mount options: per mount options
69+
* (7) optional fields: zero or more fields of the form "tag[:value]"
70+
* (8) separator: marks the end of the optional fields
71+
* (9) filesystem type: name of filesystem of the form "type[.subtype]"
72+
* (10) mount source: filesystem specific information or "none"
73+
* (11) super options: per super block options
74+
*/
75+
private static final Pattern MOUNTINFO_PATTERN = Pattern.compile(
76+
"^[^\\s]+\\s+[^\\s]+\\s+[^\\s]+\\s+" + // (1), (2), (3)
77+
"([^\\s]+)\\s+([^\\s]+)\\s+" + // (4), (5) - group 1, 2: root, mount point
78+
"[^-]+-\\s+" + // (6), (7), (8)
79+
"([^\\s]+)\\s+" + // (9) - group 3: filesystem type
80+
".*$"); // (10), (11)
81+
5382
static CgroupMetrics create() {
5483
Optional<CgroupTypeResult> optResult = null;
5584
try {
5685
optResult = determineType("/proc/self/mountinfo", "/proc/cgroups", "/proc/self/cgroup");
57-
} catch (IOException e) {
86+
} catch (IOException | UncheckedIOException e) {
5887
return null;
5988
}
6089
return create(optResult);
@@ -75,7 +104,8 @@ public static CgroupMetrics create(Optional<CgroupTypeResult> optResult) {
75104
// not ready to deal with that on a per-controller basis. Return no metrics
76105
// in that case
77106
if (result.isAnyCgroupV1Controllers() && result.isAnyCgroupV2Controllers()) {
78-
warn("Mixed cgroupv1 and cgroupv2 not supported. Metrics disabled.");
107+
Logger logger = System.getLogger("jdk.internal.platform");
108+
logger.log(Level.DEBUG, "Mixed cgroupv1 and cgroupv2 not supported. Metrics disabled.");
79109
return null;
80110
}
81111

@@ -91,11 +121,6 @@ public static CgroupMetrics create(Optional<CgroupTypeResult> optResult) {
91121
}
92122
}
93123

94-
private static void warn(String msg) {
95-
Logger logger = System.getLogger("jdk.internal.platform");
96-
logger.log(Level.DEBUG, msg);
97-
}
98-
99124
/*
100125
* Determine the type of the cgroup system (v1 - legacy or hybrid - or, v2 - unified)
101126
* based on three files:
@@ -171,15 +196,16 @@ public static Optional<CgroupTypeResult> determineType(String mountInfo,
171196
// See:
172197
// setCgroupV1Path() for the action run for cgroups v1 systems
173198
// setCgroupV2Path() for the action run for cgroups v2 systems
174-
Consumer<String[]> action = (tokens -> setCgroupV1Path(infos, tokens));
175-
if (isCgroupsV2) {
176-
action = (tokens -> setCgroupV2Path(infos, tokens));
177-
}
178-
for (String line : CgroupUtil.readAllLinesPrivileged(Paths.get(selfCgroup))) {
199+
try (Stream<String> selfCgroupLines =
200+
CgroupUtil.readFilePrivileged(Paths.get(selfCgroup))) {
201+
Consumer<String[]> action = (tokens -> setCgroupV1Path(infos, tokens));
202+
if (isCgroupsV2) {
203+
action = (tokens -> setCgroupV2Path(infos, tokens));
204+
}
179205
// The limit value of 3 is because /proc/self/cgroup contains three
180206
// colon-separated tokens per line. The last token, cgroup path, might
181207
// contain a ':'.
182-
action.accept(line.split(":", 3));
208+
selfCgroupLines.map(line -> line.split(":", 3)).forEach(action);
183209
}
184210

185211
CgroupTypeResult result = new CgroupTypeResult(isCgroupsV2,
@@ -255,8 +281,8 @@ private static void setCgroupV1Path(Map<String, CgroupInfo> infos,
255281
/**
256282
* Amends cgroup infos with mount path and mount root. The passed in
257283
* 'mntInfoLine' represents a single line in, for example,
258-
* /proc/self/mountinfo. Each line is parsed with {@link MountInfo#parse},
259-
* so as to extract the relevant tokens from the line.
284+
* /proc/self/mountinfo. Each line is matched with MOUNTINFO_PATTERN
285+
* (see above), so as to extract the relevant tokens from the line.
260286
*
261287
* Host example cgroups v1:
262288
*
@@ -277,13 +303,13 @@ private static void setCgroupV1Path(Map<String, CgroupInfo> infos,
277303
private static boolean amendCgroupInfos(String mntInfoLine,
278304
Map<String, CgroupInfo> infos,
279305
boolean isCgroupsV2) {
280-
MountInfo mountInfo = MountInfo.parse(mntInfoLine);
306+
Matcher lineMatcher = MOUNTINFO_PATTERN.matcher(mntInfoLine.trim());
281307
boolean cgroupv1ControllerFound = false;
282308
boolean cgroupv2ControllerFound = false;
283-
if (mountInfo != null) {
284-
String mountRoot = mountInfo.mountRoot;
285-
String mountPath = mountInfo.mountPath;
286-
String fsType = mountInfo.fsType;
309+
if (lineMatcher.matches()) {
310+
String mountRoot = lineMatcher.group(1);
311+
String mountPath = lineMatcher.group(2);
312+
String fsType = lineMatcher.group(3);
287313
if (fsType.equals("cgroup")) {
288314
Path p = Paths.get(mountPath);
289315
String[] controllerNames = p.getFileName().toString().split(",");
@@ -319,59 +345,6 @@ private static boolean amendCgroupInfos(String mntInfoLine,
319345
return cgroupv1ControllerFound || cgroupv2ControllerFound;
320346
}
321347

322-
private record MountInfo(String mountRoot, String mountPath, String fsType) {
323-
/*
324-
* From https://www.kernel.org/doc/Documentation/filesystems/proc.txt
325-
*
326-
* 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue
327-
* (1)(2)(3) (4) (5) (6) (7) (8) (9) (10) (11)
328-
*
329-
* (1) mount ID: unique identifier of the mount (may be reused after umount)
330-
* (2) parent ID: ID of parent (or of self for the top of the mount tree)
331-
* (3) major:minor: value of st_dev for files on filesystem
332-
* (4) root: root of the mount within the filesystem
333-
* (5) mount point: mount point relative to the process's root
334-
* (6) mount options: per mount options
335-
* (7) optional fields: zero or more fields of the form "tag[:value]"
336-
* (8) separator: marks the end of the optional fields
337-
* (9) filesystem type: name of filesystem of the form "type[.subtype]"
338-
* (10) mount source: filesystem specific information or "none"
339-
* (11) super options: per super block options
340-
*/
341-
static MountInfo parse(String line) {
342-
String mountRoot = null;
343-
String mountPath = null;
344-
345-
int separatorOrdinal = -1;
346-
// loop over space-separated tokens
347-
for (int tOrdinal = 1, tStart = 0, tEnd = line.indexOf(' '); tEnd != -1; tOrdinal++, tStart = tEnd + 1, tEnd = line.indexOf(' ', tStart)) {
348-
if (tStart == tEnd) {
349-
break; // unexpected empty token
350-
}
351-
switch (tOrdinal) {
352-
case 1, 2, 3, 6 -> {} // skip token
353-
case 4 -> mountRoot = line.substring(tStart, tEnd); // root token
354-
case 5 -> mountPath = line.substring(tStart, tEnd); // mount point token
355-
default -> {
356-
assert tOrdinal >= 7;
357-
if (separatorOrdinal == -1) {
358-
// check if we found a separator token
359-
if (tEnd - tStart == 1 && line.charAt(tStart) == '-') {
360-
separatorOrdinal = tOrdinal;
361-
}
362-
continue; // skip token
363-
}
364-
if (tOrdinal == separatorOrdinal + 1) { // filesystem type token
365-
String fsType = line.substring(tStart, tEnd);
366-
return new MountInfo(mountRoot, mountPath, fsType);
367-
}
368-
}
369-
}
370-
}
371-
return null; // parsing failed
372-
}
373-
}
374-
375348
private static void setMountPoints(CgroupInfo info, String mountPath, String mountRoot) {
376349
if (info.getMountPoint() != null) {
377350
// On some systems duplicate controllers get mounted in addition to

src/java.base/linux/classes/jdk/internal/platform/CgroupUtil.java

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,19 +26,32 @@
2626
package jdk.internal.platform;
2727

2828
import java.io.BufferedReader;
29-
import java.io.FileReader;
3029
import java.io.IOException;
31-
import java.nio.charset.StandardCharsets;
30+
import java.io.UncheckedIOException;
31+
import java.nio.file.Files;
3232
import java.nio.file.Path;
3333
import java.nio.file.Paths;
3434
import java.security.AccessController;
3535
import java.security.PrivilegedActionException;
3636
import java.security.PrivilegedExceptionAction;
37-
import java.util.ArrayList;
3837
import java.util.List;
38+
import java.util.stream.Stream;
3939

4040
public final class CgroupUtil {
4141

42+
@SuppressWarnings("removal")
43+
public static Stream<String> readFilePrivileged(Path path) throws IOException {
44+
try {
45+
PrivilegedExceptionAction<Stream<String>> pea = () -> Files.lines(path);
46+
return AccessController.doPrivileged(pea);
47+
} catch (PrivilegedActionException e) {
48+
unwrapIOExceptionAndRethrow(e);
49+
throw new InternalError(e.getCause());
50+
} catch (UncheckedIOException e) {
51+
throw e.getCause();
52+
}
53+
}
54+
4255
static void unwrapIOExceptionAndRethrow(PrivilegedActionException pae) throws IOException {
4356
Throwable x = pae.getCause();
4457
if (x instanceof IOException)
@@ -51,34 +64,29 @@ static void unwrapIOExceptionAndRethrow(PrivilegedActionException pae) throws IO
5164

5265
static String readStringValue(CgroupSubsystemController controller, String param) throws IOException {
5366
PrivilegedExceptionAction<BufferedReader> pea = () ->
54-
new BufferedReader(new FileReader(Paths.get(controller.path(), param).toString(), StandardCharsets.UTF_8));
67+
Files.newBufferedReader(Paths.get(controller.path(), param));
5568
try (@SuppressWarnings("removal") BufferedReader bufferedReader =
5669
AccessController.doPrivileged(pea)) {
5770
String line = bufferedReader.readLine();
5871
return line;
5972
} catch (PrivilegedActionException e) {
6073
unwrapIOExceptionAndRethrow(e);
6174
throw new InternalError(e.getCause());
75+
} catch (UncheckedIOException e) {
76+
throw e.getCause();
6277
}
6378
}
6479

6580
@SuppressWarnings("removal")
6681
public static List<String> readAllLinesPrivileged(Path path) throws IOException {
6782
try {
68-
PrivilegedExceptionAction<List<String>> pea = () -> {
69-
try (BufferedReader bufferedReader = new BufferedReader(new FileReader(path.toString(), StandardCharsets.UTF_8))) {
70-
String line;
71-
List<String> lines = new ArrayList<>();
72-
while ((line = bufferedReader.readLine()) != null) {
73-
lines.add(line);
74-
}
75-
return lines;
76-
}
77-
};
83+
PrivilegedExceptionAction<List<String>> pea = () -> Files.readAllLines(path);
7884
return AccessController.doPrivileged(pea);
7985
} catch (PrivilegedActionException e) {
8086
unwrapIOExceptionAndRethrow(e);
8187
throw new InternalError(e.getCause());
88+
} catch (UncheckedIOException e) {
89+
throw e.getCause();
8290
}
8391
}
8492
}

src/java.base/linux/classes/jdk/internal/platform/cgroupv1/CgroupV1SubsystemController.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ public static long getLongValueMatchingLine(CgroupSubsystemController controller
107107
}
108108

109109
public static long convertHierachicalLimitLine(String line) {
110-
String[] tokens = line.split(" ");
110+
String[] tokens = line.split("\\s");
111111
if (tokens.length == 2) {
112112
String strVal = tokens[1];
113113
return CgroupV1SubsystemController.convertStringToLong(strVal);

src/java.base/linux/classes/jdk/internal/platform/cgroupv2/CgroupV2Subsystem.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,11 @@
2626
package jdk.internal.platform.cgroupv2;
2727

2828
import java.io.IOException;
29+
import java.io.UncheckedIOException;
2930
import java.nio.file.Paths;
3031
import java.util.concurrent.TimeUnit;
3132
import java.util.function.Function;
33+
import java.util.stream.Collectors;
3234

3335
import jdk.internal.platform.CgroupInfo;
3436
import jdk.internal.platform.CgroupSubsystem;
@@ -141,7 +143,7 @@ private long getFromCpuMax(int tokenIdx) {
141143
return CgroupSubsystem.LONG_RETVAL_UNLIMITED;
142144
}
143145
// $MAX $PERIOD
144-
String[] tokens = cpuMaxRaw.split(" ");
146+
String[] tokens = cpuMaxRaw.split("\\s+");
145147
if (tokens.length != 2) {
146148
return CgroupSubsystem.LONG_RETVAL_UNLIMITED;
147149
}
@@ -327,12 +329,10 @@ public long getBlkIOServiced() {
327329

328330
private long sumTokensIOStat(Function<String, Long> mapFunc) {
329331
try {
330-
long sum = 0L;
331-
for (String line : CgroupUtil.readAllLinesPrivileged(Paths.get(unified.path(), "io.stat"))) {
332-
sum += mapFunc.apply(line);
333-
}
334-
return sum;
335-
} catch (IOException e) {
332+
return CgroupUtil.readFilePrivileged(Paths.get(unified.path(), "io.stat"))
333+
.map(mapFunc)
334+
.collect(Collectors.summingLong(e -> e));
335+
} catch (UncheckedIOException | IOException e) {
336336
return CgroupSubsystem.LONG_RETVAL_UNLIMITED;
337337
}
338338
}
@@ -359,7 +359,7 @@ private static Long ioStatLineToLong(String line, String[] matchNames) {
359359
if (line == null || EMPTY_STR.equals(line)) {
360360
return Long.valueOf(0);
361361
}
362-
String[] tokens = line.split(" ");
362+
String[] tokens = line.split("\\s+");
363363
long retval = 0;
364364
for (String t: tokens) {
365365
String[] valKeys = t.split("=");

0 commit comments

Comments
 (0)