3838import java .util .Optional ;
3939import java .util .Objects ;
4040import java .util .function .Consumer ;
41- import java .util .regex .Matcher ;
42- import java .util .regex .Pattern ;
4341import java .util .stream .Stream ;
4442
4543import jdk .internal .platform .cgroupv1 .CgroupV1Subsystem ;
@@ -54,31 +52,6 @@ public class CgroupSubsystemFactory {
5452 private static final String MEMORY_CTRL = "memory" ;
5553 private static final String PIDS_CTRL = "pids" ;
5654
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-
8255 static CgroupMetrics create () {
8356 Optional <CgroupTypeResult > optResult = null ;
8457 try {
@@ -285,8 +258,8 @@ private static void setCgroupV1Path(Map<String, CgroupInfo> infos,
285258 /**
286259 * Amends cgroup infos with mount path and mount root. The passed in
287260 * 'mntInfoLine' represents a single line in, for example,
288- * /proc/self/mountinfo. Each line is matched with MOUNTINFO_PATTERN
289- * (see above), so as to extract the relevant tokens from the line.
261+ * /proc/self/mountinfo. Each line is parsed with {@link MountInfo#parse},
262+ * so as to extract the relevant tokens from the line.
290263 *
291264 * Host example cgroups v1:
292265 *
@@ -307,13 +280,13 @@ private static void setCgroupV1Path(Map<String, CgroupInfo> infos,
307280 private static boolean amendCgroupInfos (String mntInfoLine ,
308281 Map <String , CgroupInfo > infos ,
309282 boolean isCgroupsV2 ) {
310- Matcher lineMatcher = MOUNTINFO_PATTERN . matcher (mntInfoLine . trim () );
283+ MountInfo mountInfo = MountInfo . parse (mntInfoLine );
311284 boolean cgroupv1ControllerFound = false ;
312285 boolean cgroupv2ControllerFound = false ;
313- if (lineMatcher . matches () ) {
314- String mountRoot = lineMatcher . group ( 1 ) ;
315- String mountPath = lineMatcher . group ( 2 ) ;
316- String fsType = lineMatcher . group ( 3 ) ;
286+ if (mountInfo != null ) {
287+ String mountRoot = mountInfo . mountRoot ;
288+ String mountPath = mountInfo . mountPath ;
289+ String fsType = mountInfo . fsType ;
317290 if (fsType .equals ("cgroup" )) {
318291 Path p = Paths .get (mountPath );
319292 String [] controllerNames = p .getFileName ().toString ().split ("," );
@@ -349,6 +322,59 @@ private static boolean amendCgroupInfos(String mntInfoLine,
349322 return cgroupv1ControllerFound || cgroupv2ControllerFound ;
350323 }
351324
325+ private record MountInfo (String mountRoot , String mountPath , String fsType ) {
326+ /*
327+ * From https://www.kernel.org/doc/Documentation/filesystems/proc.txt
328+ *
329+ * 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue
330+ * (1)(2)(3) (4) (5) (6) (7) (8) (9) (10) (11)
331+ *
332+ * (1) mount ID: unique identifier of the mount (may be reused after umount)
333+ * (2) parent ID: ID of parent (or of self for the top of the mount tree)
334+ * (3) major:minor: value of st_dev for files on filesystem
335+ * (4) root: root of the mount within the filesystem
336+ * (5) mount point: mount point relative to the process's root
337+ * (6) mount options: per mount options
338+ * (7) optional fields: zero or more fields of the form "tag[:value]"
339+ * (8) separator: marks the end of the optional fields
340+ * (9) filesystem type: name of filesystem of the form "type[.subtype]"
341+ * (10) mount source: filesystem specific information or "none"
342+ * (11) super options: per super block options
343+ */
344+ static MountInfo parse (String line ) {
345+ String mountRoot = null ;
346+ String mountPath = null ;
347+
348+ int separatorOrdinal = -1 ;
349+ // loop over space-separated tokens
350+ for (int tOrdinal = 1 , tStart = 0 , tEnd = line .indexOf (' ' ); tEnd != -1 ; tOrdinal ++, tStart = tEnd + 1 , tEnd = line .indexOf (' ' , tStart )) {
351+ if (tStart == tEnd ) {
352+ break ; // unexpected empty token
353+ }
354+ switch (tOrdinal ) {
355+ case 1 , 2 , 3 , 6 -> {} // skip token
356+ case 4 -> mountRoot = line .substring (tStart , tEnd ); // root token
357+ case 5 -> mountPath = line .substring (tStart , tEnd ); // mount point token
358+ default -> {
359+ assert tOrdinal >= 7 ;
360+ if (separatorOrdinal == -1 ) {
361+ // check if we found a separator token
362+ if (tEnd - tStart == 1 && line .charAt (tStart ) == '-' ) {
363+ separatorOrdinal = tOrdinal ;
364+ }
365+ continue ; // skip token
366+ }
367+ if (tOrdinal == separatorOrdinal + 1 ) { // filesystem type token
368+ String fsType = line .substring (tStart , tEnd );
369+ return new MountInfo (mountRoot , mountPath , fsType );
370+ }
371+ }
372+ }
373+ }
374+ return null ; // parsing failed
375+ }
376+ }
377+
352378 private static void setMountPoints (CgroupInfo info , String mountPath , String mountRoot ) {
353379 if (info .getMountPoint () != null ) {
354380 // On some systems duplicate controllers get mounted in addition to
0 commit comments