mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 15:24:43 +02:00
8217338: [Containers] Improve systemd slice memory limit support
Use hierachical memory limit in addition to memory_limits_in_bytes Reviewed-by: bobv, dholmes
This commit is contained in:
parent
b1ae2d0bf1
commit
73d7e8f86c
4 changed files with 207 additions and 26 deletions
|
@ -122,7 +122,25 @@ class CgroupSubsystem: CHeapObj<mtInternal> {
|
||||||
char *subsystem_path() { return _path; }
|
char *subsystem_path() { return _path; }
|
||||||
};
|
};
|
||||||
|
|
||||||
CgroupSubsystem* memory = NULL;
|
class CgroupMemorySubsystem: CgroupSubsystem {
|
||||||
|
friend class OSContainer;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/* Some container runtimes set limits via cgroup
|
||||||
|
* hierarchy. If set to true consider also memory.stat
|
||||||
|
* file if everything else seems unlimited */
|
||||||
|
bool _uses_mem_hierarchy;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CgroupMemorySubsystem(char *root, char *mountpoint) : CgroupSubsystem::CgroupSubsystem(root, mountpoint) {
|
||||||
|
_uses_mem_hierarchy = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_hierarchical() { return _uses_mem_hierarchy; }
|
||||||
|
void set_hierarchical(bool value) { _uses_mem_hierarchy = value; }
|
||||||
|
};
|
||||||
|
|
||||||
|
CgroupMemorySubsystem* memory = NULL;
|
||||||
CgroupSubsystem* cpuset = NULL;
|
CgroupSubsystem* cpuset = NULL;
|
||||||
CgroupSubsystem* cpu = NULL;
|
CgroupSubsystem* cpu = NULL;
|
||||||
CgroupSubsystem* cpuacct = NULL;
|
CgroupSubsystem* cpuacct = NULL;
|
||||||
|
@ -131,21 +149,24 @@ typedef char * cptr;
|
||||||
|
|
||||||
PRAGMA_DIAG_PUSH
|
PRAGMA_DIAG_PUSH
|
||||||
PRAGMA_FORMAT_NONLITERAL_IGNORED
|
PRAGMA_FORMAT_NONLITERAL_IGNORED
|
||||||
template <typename T> int subsystem_file_contents(CgroupSubsystem* c,
|
template <typename T> int subsystem_file_line_contents(CgroupSubsystem* c,
|
||||||
const char *filename,
|
const char *filename,
|
||||||
|
const char *matchline,
|
||||||
const char *scan_fmt,
|
const char *scan_fmt,
|
||||||
T returnval) {
|
T returnval) {
|
||||||
FILE *fp = NULL;
|
FILE *fp = NULL;
|
||||||
char *p;
|
char *p;
|
||||||
char file[MAXPATHLEN+1];
|
char file[MAXPATHLEN+1];
|
||||||
char buf[MAXPATHLEN+1];
|
char buf[MAXPATHLEN+1];
|
||||||
|
char discard[MAXPATHLEN+1];
|
||||||
|
bool found_match = false;
|
||||||
|
|
||||||
if (c == NULL) {
|
if (c == NULL) {
|
||||||
log_debug(os, container)("subsystem_file_contents: CgroupSubsytem* is NULL");
|
log_debug(os, container)("subsystem_file_line_contents: CgroupSubsytem* is NULL");
|
||||||
return OSCONTAINER_ERROR;
|
return OSCONTAINER_ERROR;
|
||||||
}
|
}
|
||||||
if (c->subsystem_path() == NULL) {
|
if (c->subsystem_path() == NULL) {
|
||||||
log_debug(os, container)("subsystem_file_contents: subsystem path is NULL");
|
log_debug(os, container)("subsystem_file_line_contents: subsystem path is NULL");
|
||||||
return OSCONTAINER_ERROR;
|
return OSCONTAINER_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,16 +181,32 @@ template <typename T> int subsystem_file_contents(CgroupSubsystem* c,
|
||||||
log_trace(os, container)("Path to %s is %s", filename, file);
|
log_trace(os, container)("Path to %s is %s", filename, file);
|
||||||
fp = fopen(file, "r");
|
fp = fopen(file, "r");
|
||||||
if (fp != NULL) {
|
if (fp != NULL) {
|
||||||
p = fgets(buf, MAXPATHLEN, fp);
|
int err = 0;
|
||||||
if (p != NULL) {
|
while ((p = fgets(buf, MAXPATHLEN, fp)) != NULL) {
|
||||||
int matched = sscanf(p, scan_fmt, returnval);
|
found_match = false;
|
||||||
if (matched == 1) {
|
if (matchline == NULL) {
|
||||||
|
// single-line file case
|
||||||
|
int matched = sscanf(p, scan_fmt, returnval);
|
||||||
|
found_match = (matched == 1);
|
||||||
|
} else {
|
||||||
|
// multi-line file case
|
||||||
|
if (strstr(p, matchline) != NULL) {
|
||||||
|
// discard matchline string prefix
|
||||||
|
int matched = sscanf(p, scan_fmt, discard, returnval);
|
||||||
|
found_match = (matched == 2);
|
||||||
|
} else {
|
||||||
|
continue; // substring not found
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (found_match) {
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
|
err = 1;
|
||||||
log_debug(os, container)("Type %s not found in file %s", scan_fmt, file);
|
log_debug(os, container)("Type %s not found in file %s", scan_fmt, file);
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
if (err == 0) {
|
||||||
log_debug(os, container)("Empty file %s", file);
|
log_debug(os, container)("Empty file %s", file);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -186,10 +223,11 @@ PRAGMA_DIAG_POP
|
||||||
return_type variable; \
|
return_type variable; \
|
||||||
{ \
|
{ \
|
||||||
int err; \
|
int err; \
|
||||||
err = subsystem_file_contents(subsystem, \
|
err = subsystem_file_line_contents(subsystem, \
|
||||||
filename, \
|
filename, \
|
||||||
scan_fmt, \
|
NULL, \
|
||||||
&variable); \
|
scan_fmt, \
|
||||||
|
&variable); \
|
||||||
if (err != 0) \
|
if (err != 0) \
|
||||||
return (return_type) OSCONTAINER_ERROR; \
|
return (return_type) OSCONTAINER_ERROR; \
|
||||||
\
|
\
|
||||||
|
@ -201,16 +239,33 @@ PRAGMA_DIAG_POP
|
||||||
char variable[bufsize]; \
|
char variable[bufsize]; \
|
||||||
{ \
|
{ \
|
||||||
int err; \
|
int err; \
|
||||||
err = subsystem_file_contents(subsystem, \
|
err = subsystem_file_line_contents(subsystem, \
|
||||||
filename, \
|
filename, \
|
||||||
scan_fmt, \
|
NULL, \
|
||||||
variable); \
|
scan_fmt, \
|
||||||
|
variable); \
|
||||||
if (err != 0) \
|
if (err != 0) \
|
||||||
return (return_type) NULL; \
|
return (return_type) NULL; \
|
||||||
\
|
\
|
||||||
log_trace(os, container)(logstring, variable); \
|
log_trace(os, container)(logstring, variable); \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define GET_CONTAINER_INFO_LINE(return_type, subsystem, filename, \
|
||||||
|
matchline, logstring, scan_fmt, variable) \
|
||||||
|
return_type variable; \
|
||||||
|
{ \
|
||||||
|
int err; \
|
||||||
|
err = subsystem_file_line_contents(subsystem, \
|
||||||
|
filename, \
|
||||||
|
matchline, \
|
||||||
|
scan_fmt, \
|
||||||
|
&variable); \
|
||||||
|
if (err != 0) \
|
||||||
|
return (return_type) OSCONTAINER_ERROR; \
|
||||||
|
\
|
||||||
|
log_trace(os, container)(logstring, variable); \
|
||||||
|
}
|
||||||
|
|
||||||
/* init
|
/* init
|
||||||
*
|
*
|
||||||
* Initialize the container support and determine if
|
* Initialize the container support and determine if
|
||||||
|
@ -266,7 +321,7 @@ void OSContainer::init() {
|
||||||
}
|
}
|
||||||
while ((token = strsep(&cptr, ",")) != NULL) {
|
while ((token = strsep(&cptr, ",")) != NULL) {
|
||||||
if (strcmp(token, "memory") == 0) {
|
if (strcmp(token, "memory") == 0) {
|
||||||
memory = new CgroupSubsystem(tmproot, tmpmount);
|
memory = new CgroupMemorySubsystem(tmproot, tmpmount);
|
||||||
} else if (strcmp(token, "cpuset") == 0) {
|
} else if (strcmp(token, "cpuset") == 0) {
|
||||||
cpuset = new CgroupSubsystem(tmproot, tmpmount);
|
cpuset = new CgroupSubsystem(tmproot, tmpmount);
|
||||||
} else if (strcmp(token, "cpu") == 0) {
|
} else if (strcmp(token, "cpu") == 0) {
|
||||||
|
@ -344,6 +399,10 @@ void OSContainer::init() {
|
||||||
while ((token = strsep(&controllers, ",")) != NULL) {
|
while ((token = strsep(&controllers, ",")) != NULL) {
|
||||||
if (strcmp(token, "memory") == 0) {
|
if (strcmp(token, "memory") == 0) {
|
||||||
memory->set_subsystem_path(base);
|
memory->set_subsystem_path(base);
|
||||||
|
jlong hierarchy = uses_mem_hierarchy();
|
||||||
|
if (hierarchy > 0) {
|
||||||
|
memory->set_hierarchical(true);
|
||||||
|
}
|
||||||
} else if (strcmp(token, "cpuset") == 0) {
|
} else if (strcmp(token, "cpuset") == 0) {
|
||||||
cpuset->set_subsystem_path(base);
|
cpuset->set_subsystem_path(base);
|
||||||
} else if (strcmp(token, "cpu") == 0) {
|
} else if (strcmp(token, "cpu") == 0) {
|
||||||
|
@ -360,6 +419,7 @@ void OSContainer::init() {
|
||||||
// command line arguments have been processed.
|
// command line arguments have been processed.
|
||||||
if ((mem_limit = memory_limit_in_bytes()) > 0) {
|
if ((mem_limit = memory_limit_in_bytes()) > 0) {
|
||||||
os::Linux::set_physical_memory(mem_limit);
|
os::Linux::set_physical_memory(mem_limit);
|
||||||
|
log_info(os, container)("Memory Limit is: " JLONG_FORMAT, mem_limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
_is_containerized = true;
|
_is_containerized = true;
|
||||||
|
@ -374,6 +434,21 @@ const char * OSContainer::container_type() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* uses_mem_hierarchy
|
||||||
|
*
|
||||||
|
* Return whether or not hierarchical cgroup accounting is being
|
||||||
|
* done.
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* A number > 0 if true, or
|
||||||
|
* OSCONTAINER_ERROR for not supported
|
||||||
|
*/
|
||||||
|
jlong OSContainer::uses_mem_hierarchy() {
|
||||||
|
GET_CONTAINER_INFO(jlong, memory, "/memory.use_hierarchy",
|
||||||
|
"Use Hierarchy is: " JLONG_FORMAT, JLONG_FORMAT, use_hierarchy);
|
||||||
|
return use_hierarchy;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* memory_limit_in_bytes
|
/* memory_limit_in_bytes
|
||||||
*
|
*
|
||||||
|
@ -389,7 +464,18 @@ jlong OSContainer::memory_limit_in_bytes() {
|
||||||
"Memory Limit is: " JULONG_FORMAT, JULONG_FORMAT, memlimit);
|
"Memory Limit is: " JULONG_FORMAT, JULONG_FORMAT, memlimit);
|
||||||
|
|
||||||
if (memlimit >= _unlimited_memory) {
|
if (memlimit >= _unlimited_memory) {
|
||||||
log_trace(os, container)("Memory Limit is: Unlimited");
|
log_trace(os, container)("Non-Hierarchical Memory Limit is: Unlimited");
|
||||||
|
if (memory->is_hierarchical()) {
|
||||||
|
const char* matchline = "hierarchical_memory_limit";
|
||||||
|
char* format = "%s " JULONG_FORMAT;
|
||||||
|
GET_CONTAINER_INFO_LINE(julong, memory, "/memory.stat", matchline,
|
||||||
|
"Hierarchical Memory Limit is: " JULONG_FORMAT, format, hier_memlimit)
|
||||||
|
if (hier_memlimit >= _unlimited_memory) {
|
||||||
|
log_trace(os, container)("Hierarchical Memory Limit is: Unlimited");
|
||||||
|
} else {
|
||||||
|
return (jlong)hier_memlimit;
|
||||||
|
}
|
||||||
|
}
|
||||||
return (jlong)-1;
|
return (jlong)-1;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -401,7 +487,18 @@ jlong OSContainer::memory_and_swap_limit_in_bytes() {
|
||||||
GET_CONTAINER_INFO(julong, memory, "/memory.memsw.limit_in_bytes",
|
GET_CONTAINER_INFO(julong, memory, "/memory.memsw.limit_in_bytes",
|
||||||
"Memory and Swap Limit is: " JULONG_FORMAT, JULONG_FORMAT, memswlimit);
|
"Memory and Swap Limit is: " JULONG_FORMAT, JULONG_FORMAT, memswlimit);
|
||||||
if (memswlimit >= _unlimited_memory) {
|
if (memswlimit >= _unlimited_memory) {
|
||||||
log_trace(os, container)("Memory and Swap Limit is: Unlimited");
|
log_trace(os, container)("Non-Hierarchical Memory and Swap Limit is: Unlimited");
|
||||||
|
if (memory->is_hierarchical()) {
|
||||||
|
const char* matchline = "hierarchical_memsw_limit";
|
||||||
|
char* format = "%s " JULONG_FORMAT;
|
||||||
|
GET_CONTAINER_INFO_LINE(julong, memory, "/memory.stat", matchline,
|
||||||
|
"Hierarchical Memory and Swap Limit is : " JULONG_FORMAT, format, hier_memlimit)
|
||||||
|
if (hier_memlimit >= _unlimited_memory) {
|
||||||
|
log_trace(os, container)("Hierarchical Memory and Swap Limit is: Unlimited");
|
||||||
|
} else {
|
||||||
|
return (jlong)hier_memlimit;
|
||||||
|
}
|
||||||
|
}
|
||||||
return (jlong)-1;
|
return (jlong)-1;
|
||||||
} else {
|
} else {
|
||||||
return (jlong)memswlimit;
|
return (jlong)memswlimit;
|
||||||
|
|
|
@ -42,6 +42,7 @@ class OSContainer: AllStatic {
|
||||||
static inline bool is_containerized();
|
static inline bool is_containerized();
|
||||||
static const char * container_type();
|
static const char * container_type();
|
||||||
|
|
||||||
|
static jlong uses_mem_hierarchy();
|
||||||
static jlong memory_limit_in_bytes();
|
static jlong memory_limit_in_bytes();
|
||||||
static jlong memory_and_swap_limit_in_bytes();
|
static jlong memory_and_swap_limit_in_bytes();
|
||||||
static jlong memory_soft_limit_in_bytes();
|
static jlong memory_soft_limit_in_bytes();
|
||||||
|
|
|
@ -25,15 +25,16 @@
|
||||||
|
|
||||||
package jdk.internal.platform.cgroupv1;
|
package jdk.internal.platform.cgroupv1;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import jdk.internal.platform.cgroupv1.SubSystem.MemorySubSystem;
|
||||||
|
|
||||||
public class Metrics implements jdk.internal.platform.Metrics {
|
public class Metrics implements jdk.internal.platform.Metrics {
|
||||||
private SubSystem memory;
|
private MemorySubSystem memory;
|
||||||
private SubSystem cpu;
|
private SubSystem cpu;
|
||||||
private SubSystem cpuacct;
|
private SubSystem cpuacct;
|
||||||
private SubSystem cpuset;
|
private SubSystem cpuset;
|
||||||
|
@ -133,7 +134,7 @@ public class Metrics implements jdk.internal.platform.Metrics {
|
||||||
for (String subsystemName: subsystemNames) {
|
for (String subsystemName: subsystemNames) {
|
||||||
switch (subsystemName) {
|
switch (subsystemName) {
|
||||||
case "memory":
|
case "memory":
|
||||||
metric.setMemorySubSystem(new SubSystem(mountentry[3], mountentry[4]));
|
metric.setMemorySubSystem(new MemorySubSystem(mountentry[3], mountentry[4]));
|
||||||
break;
|
break;
|
||||||
case "cpuset":
|
case "cpuset":
|
||||||
metric.setCpuSetSubSystem(new SubSystem(mountentry[3], mountentry[4]));
|
metric.setCpuSetSubSystem(new SubSystem(mountentry[3], mountentry[4]));
|
||||||
|
@ -195,6 +196,11 @@ public class Metrics implements jdk.internal.platform.Metrics {
|
||||||
|
|
||||||
if (subsystem != null) {
|
if (subsystem != null) {
|
||||||
subsystem.setPath(base);
|
subsystem.setPath(base);
|
||||||
|
if (subsystem instanceof MemorySubSystem) {
|
||||||
|
MemorySubSystem memorySubSystem = (MemorySubSystem)subsystem;
|
||||||
|
boolean isHierarchial = getHierarchical(memorySubSystem);
|
||||||
|
memorySubSystem.setHierarchical(isHierarchial);
|
||||||
|
}
|
||||||
metric.setActiveSubSystems();
|
metric.setActiveSubSystems();
|
||||||
}
|
}
|
||||||
if (subsystem2 != null) {
|
if (subsystem2 != null) {
|
||||||
|
@ -203,6 +209,11 @@ public class Metrics implements jdk.internal.platform.Metrics {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static boolean getHierarchical(MemorySubSystem subsystem) {
|
||||||
|
long hierarchical = SubSystem.getLongValue(subsystem, "memory.use_hierarchy");
|
||||||
|
return hierarchical > 0;
|
||||||
|
}
|
||||||
|
|
||||||
private void setActiveSubSystems() {
|
private void setActiveSubSystems() {
|
||||||
activeSubSystems = true;
|
activeSubSystems = true;
|
||||||
}
|
}
|
||||||
|
@ -211,7 +222,7 @@ public class Metrics implements jdk.internal.platform.Metrics {
|
||||||
return activeSubSystems;
|
return activeSubSystems;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setMemorySubSystem(SubSystem memory) {
|
private void setMemorySubSystem(MemorySubSystem memory) {
|
||||||
this.memory = memory;
|
this.memory = memory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -366,9 +377,29 @@ public class Metrics implements jdk.internal.platform.Metrics {
|
||||||
|
|
||||||
public long getMemoryLimit() {
|
public long getMemoryLimit() {
|
||||||
long retval = SubSystem.getLongValue(memory, "memory.limit_in_bytes");
|
long retval = SubSystem.getLongValue(memory, "memory.limit_in_bytes");
|
||||||
|
if (retval > unlimited_minimum) {
|
||||||
|
if (memory.isHierarchical()) {
|
||||||
|
// memory.limit_in_bytes returned unlimited, attempt
|
||||||
|
// hierarchical memory limit
|
||||||
|
String match = "hierarchical_memory_limit";
|
||||||
|
retval = SubSystem.getLongValueMatchingLine(memory,
|
||||||
|
"memory.stat",
|
||||||
|
match,
|
||||||
|
Metrics::convertHierachicalLimitLine);
|
||||||
|
}
|
||||||
|
}
|
||||||
return retval > unlimited_minimum ? -1L : retval;
|
return retval > unlimited_minimum ? -1L : retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static long convertHierachicalLimitLine(String line) {
|
||||||
|
String[] tokens = line.split("\\s");
|
||||||
|
if (tokens.length == 2) {
|
||||||
|
String strVal = tokens[1];
|
||||||
|
return SubSystem.convertStringToLong(strVal);
|
||||||
|
}
|
||||||
|
return unlimited_minimum + 1; // unlimited
|
||||||
|
}
|
||||||
|
|
||||||
public long getMemoryMaxUsage() {
|
public long getMemoryMaxUsage() {
|
||||||
return SubSystem.getLongValue(memory, "memory.max_usage_in_bytes");
|
return SubSystem.getLongValue(memory, "memory.max_usage_in_bytes");
|
||||||
}
|
}
|
||||||
|
@ -417,6 +448,17 @@ public class Metrics implements jdk.internal.platform.Metrics {
|
||||||
|
|
||||||
public long getMemoryAndSwapLimit() {
|
public long getMemoryAndSwapLimit() {
|
||||||
long retval = SubSystem.getLongValue(memory, "memory.memsw.limit_in_bytes");
|
long retval = SubSystem.getLongValue(memory, "memory.memsw.limit_in_bytes");
|
||||||
|
if (retval > unlimited_minimum) {
|
||||||
|
if (memory.isHierarchical()) {
|
||||||
|
// memory.memsw.limit_in_bytes returned unlimited, attempt
|
||||||
|
// hierarchical memory limit
|
||||||
|
String match = "hierarchical_memsw_limit";
|
||||||
|
retval = SubSystem.getLongValueMatchingLine(memory,
|
||||||
|
"memory.stat",
|
||||||
|
match,
|
||||||
|
Metrics::convertHierachicalLimitLine);
|
||||||
|
}
|
||||||
|
}
|
||||||
return retval > unlimited_minimum ? -1L : retval;
|
return retval > unlimited_minimum ? -1L : retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,10 +29,11 @@ import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.function.Function;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
public class SubSystem {
|
public class SubSystem {
|
||||||
|
@ -99,10 +100,32 @@ public class SubSystem {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static long getLongValueMatchingLine(SubSystem subsystem,
|
||||||
|
String param,
|
||||||
|
String match,
|
||||||
|
Function<String, Long> conversion) {
|
||||||
|
long retval = Metrics.unlimited_minimum + 1; // default unlimited
|
||||||
|
try {
|
||||||
|
List<String> lines = Files.readAllLines(Paths.get(subsystem.path(), param));
|
||||||
|
for (String line: lines) {
|
||||||
|
if (line.contains(match)) {
|
||||||
|
retval = conversion.apply(line);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
// Ignore. Default is unlimited.
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
public static long getLongValue(SubSystem subsystem, String parm) {
|
public static long getLongValue(SubSystem subsystem, String parm) {
|
||||||
String strval = getStringValue(subsystem, parm);
|
String strval = getStringValue(subsystem, parm);
|
||||||
long retval = 0;
|
return convertStringToLong(strval);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long convertStringToLong(String strval) {
|
||||||
|
long retval = 0;
|
||||||
if (strval == null) return 0L;
|
if (strval == null) return 0L;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -215,4 +238,22 @@ public class SubSystem {
|
||||||
|
|
||||||
return ints;
|
return ints;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class MemorySubSystem extends SubSystem {
|
||||||
|
|
||||||
|
private boolean hierarchical;
|
||||||
|
|
||||||
|
public MemorySubSystem(String root, String mountPoint) {
|
||||||
|
super(root, mountPoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isHierarchical() {
|
||||||
|
return hierarchical;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setHierarchical(boolean hierarchical) {
|
||||||
|
this.hierarchical = hierarchical;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue