提交 fc659ce5 编写于 作者: M minqi

7090324: gclog rotation via external tool

Summary: GC log rotation can be set via java command line, but customer sometime need to sync with OS level rotation setting.
Reviewed-by: sla, minqi, ehelin
Contributed-by: suenaga.yasumasa@lab.ntt.co.jp
上级 c42a215d
......@@ -1880,21 +1880,19 @@ static bool verify_serial_gc_flags() {
// check if do gclog rotation
// +UseGCLogFileRotation is a must,
// no gc log rotation when log file not supplied or
// NumberOfGCLogFiles is 0, or GCLogFileSize is 0
// NumberOfGCLogFiles is 0
void check_gclog_consistency() {
if (UseGCLogFileRotation) {
if ((Arguments::gc_log_filename() == NULL) ||
(NumberOfGCLogFiles == 0) ||
(GCLogFileSize == 0)) {
if ((Arguments::gc_log_filename() == NULL) || (NumberOfGCLogFiles == 0)) {
jio_fprintf(defaultStream::output_stream(),
"To enable GC log rotation, use -Xloggc:<filename> -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=<num_of_files> -XX:GCLogFileSize=<num_of_size>[k|K|m|M|g|G]\n"
"where num_of_file > 0 and num_of_size > 0\n"
"To enable GC log rotation, use -Xloggc:<filename> -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=<num_of_files>\n"
"where num_of_file > 0\n"
"GC log rotation is turned off\n");
UseGCLogFileRotation = false;
}
}
if (UseGCLogFileRotation && GCLogFileSize < 8*K) {
if (UseGCLogFileRotation && (GCLogFileSize != 0) && (GCLogFileSize < 8*K)) {
FLAG_SET_CMDLINE(uintx, GCLogFileSize, 8*K);
jio_fprintf(defaultStream::output_stream(),
"GCLogFileSize changed to minimum 8K\n");
......
......@@ -2422,9 +2422,9 @@ class CommandLineFlags {
"Number of gclog files in rotation " \
"(default: 0, no rotation)") \
\
product(uintx, GCLogFileSize, 0, \
"GC log file size (default: 0 bytes, no rotation). " \
"It requires UseGCLogFileRotation") \
product(uintx, GCLogFileSize, 8*K, \
"GC log file size, requires UseGCLogFileRotation. " \
"Set to 0 to only trigger rotation via jcmd") \
\
/* JVMTI heap profiling */ \
\
......
......@@ -535,7 +535,7 @@ void SafepointSynchronize::do_cleanup_tasks() {
// rotate log files?
if (UseGCLogFileRotation) {
gclog_or_tty->rotate_log();
gclog_or_tty->rotate_log(false);
}
if (MemTracker::is_on()) {
......
......@@ -94,6 +94,7 @@
template(JFRCheckpoint) \
template(Exit) \
template(LinuxDllLoad) \
template(RotateGCLog) \
class VM_Operation: public CHeapObj<mtInternal> {
public:
......@@ -397,4 +398,15 @@ class VM_Exit: public VM_Operation {
void doit();
};
class VM_RotateGCLog: public VM_Operation {
private:
outputStream* _out;
public:
VM_RotateGCLog(outputStream* st) : _out(st) {}
VMOp_Type type() const { return VMOp_RotateGCLog; }
void doit() { gclog_or_tty->rotate_log(true, _out); }
};
#endif // SHARE_VM_RUNTIME_VM_OPERATIONS_HPP
......@@ -53,6 +53,7 @@ void DCmdRegistrant::register_dcmds(){
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassStatsDCmd>(full_export, true, false));
#endif // INCLUDE_SERVICES
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ThreadDumpDCmd>(full_export, true, false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<RotateGCLogDCmd>(full_export, true, false));
// Enhanced JMX Agent Support
// These commands won't be exported via the DiagnosticCommandMBean until an
......@@ -650,3 +651,11 @@ void JMXStopRemoteDCmd::execute(DCmdSource source, TRAPS) {
JavaCalls::call_static(&result, ik, vmSymbols::stopRemoteAgent_name(), vmSymbols::void_method_signature(), CHECK);
}
void RotateGCLogDCmd::execute(DCmdSource source, TRAPS) {
if (UseGCLogFileRotation) {
VM_RotateGCLog rotateop(output());
VMThread::execute(&rotateop);
} else {
output()->print_cr("Target VM does not support GC log file rotation.");
}
}
......@@ -360,4 +360,21 @@ public:
virtual void execute(DCmdSource source, TRAPS);
};
class RotateGCLogDCmd : public DCmd {
public:
RotateGCLogDCmd(outputStream* output, bool heap) : DCmd(output, heap) {}
static const char* name() { return "GC.rotate_log"; }
static const char* description() {
return "Force the GC log file to be rotated.";
}
static const char* impact() { return "Low"; }
virtual void execute(DCmdSource source, TRAPS);
static int num_arguments() { return 0; }
static const JavaPermission permission() {
JavaPermission p = {"java.lang.management.ManagementPermission",
"control", NULL};
return p;
}
};
#endif // SHARE_VM_SERVICES_DIAGNOSTICCOMMAND_HPP
......@@ -662,13 +662,13 @@ void gcLogFileStream::write(const char* s, size_t len) {
// write to gc log file at safepoint. If in future, changes made for mutator threads or
// concurrent GC threads to run parallel with VMThread at safepoint, write and rotate_log
// must be synchronized.
void gcLogFileStream::rotate_log() {
void gcLogFileStream::rotate_log(bool force, outputStream* out) {
char time_msg[FILENAMEBUFLEN];
char time_str[EXTRACHARLEN];
char current_file_name[FILENAMEBUFLEN];
char renamed_file_name[FILENAMEBUFLEN];
if (_bytes_written < (jlong)GCLogFileSize) {
if (!should_rotate(force)) {
return;
}
......@@ -685,6 +685,11 @@ void gcLogFileStream::rotate_log() {
jio_snprintf(time_msg, sizeof(time_msg), "File %s rotated at %s\n",
_file_name, os::local_time_string((char *)time_str, sizeof(time_str)));
write(time_msg, strlen(time_msg));
if (out != NULL) {
out->print(time_msg);
}
dump_loggc_header();
return;
}
......@@ -706,12 +711,18 @@ void gcLogFileStream::rotate_log() {
_file_name, _cur_file_num);
jio_snprintf(current_file_name, filename_len + EXTRACHARLEN, "%s.%d" CURRENTAPPX,
_file_name, _cur_file_num);
jio_snprintf(time_msg, sizeof(time_msg), "%s GC log file has reached the"
" maximum size. Saved as %s\n",
const char* msg = force ? "GC log rotation request has been received."
: "GC log file has reached the maximum size.";
jio_snprintf(time_msg, sizeof(time_msg), "%s %s Saved as %s\n",
os::local_time_string((char *)time_str, sizeof(time_str)),
renamed_file_name);
msg, renamed_file_name);
write(time_msg, strlen(time_msg));
if (out != NULL) {
out->print(time_msg);
}
fclose(_file);
_file = NULL;
......@@ -752,6 +763,11 @@ void gcLogFileStream::rotate_log() {
os::local_time_string((char *)time_str, sizeof(time_str)),
current_file_name);
write(time_msg, strlen(time_msg));
if (out != NULL) {
out->print(time_msg);
}
dump_loggc_header();
// remove the existing file
if (access(current_file_name, F_OK) == 0) {
......
......@@ -115,7 +115,7 @@ class outputStream : public ResourceObj {
// flushing
virtual void flush() {}
virtual void write(const char* str, size_t len) = 0;
virtual void rotate_log() {} // GC log rotation
virtual void rotate_log(bool force, outputStream* out = NULL) {} // GC log rotation
virtual ~outputStream() {} // close properly on deletion
void dec_cr() { dec(); cr(); }
......@@ -240,8 +240,15 @@ class gcLogFileStream : public fileStream {
gcLogFileStream(const char* file_name);
~gcLogFileStream();
virtual void write(const char* c, size_t len);
virtual void rotate_log();
virtual void rotate_log(bool force, outputStream* out = NULL);
void dump_loggc_header();
/* If "force" sets true, force log file rotation from outside JVM */
bool should_rotate(bool force) {
return force ||
((GCLogFileSize != 0) && ((uintx)_bytes_written >= GCLogFileSize));
}
};
#ifndef PRODUCT
......
/*
* Copyright (c) 2014, 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.
*
* 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 TestGCLogRotationViaJcmd.java
* @bug 7090324
* @summary test for gc log rotation via jcmd
* @library /testlibrary
* @run main/othervm -Xloggc:test.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=3 TestGCLogRotationViaJcmd
*
*/
import com.oracle.java.testlibrary.*;
import java.io.File;
import java.io.FilenameFilter;
public class TestGCLogRotationViaJcmd {
static final File currentDirectory = new File(".");
static final String LOG_FILE_NAME = "test.log";
static final int NUM_LOGS = 3;
static FilenameFilter logFilter = new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.startsWith(LOG_FILE_NAME);
}
};
public static void main(String[] args) throws Exception {
// Grab the pid from the current java process
String pid = Integer.toString(ProcessTools.getProcessId());
// Create a JDKToolLauncher
JDKToolLauncher jcmd = JDKToolLauncher.create("jcmd")
.addToolArg(pid)
.addToolArg("GC.rotate_log");
for (int times = 1; times < NUM_LOGS; times++) {
// Run jcmd <pid> GC.rotate_log
ProcessBuilder pb = new ProcessBuilder(jcmd.getCommand());
// Make sure we didn't crash
OutputAnalyzer output = new OutputAnalyzer(pb.start());
output.shouldHaveExitValue(0);
}
// GC log check
File[] logs = currentDirectory.listFiles(logFilter);
if (logs.length != NUM_LOGS) {
throw new Error("There are only " + logs.length
+ " logs instead " + NUM_LOGS);
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册