提交 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,24 +1880,22 @@ static bool verify_serial_gc_flags() { ...@@ -1880,24 +1880,22 @@ static bool verify_serial_gc_flags() {
// check if do gclog rotation // check if do gclog rotation
// +UseGCLogFileRotation is a must, // +UseGCLogFileRotation is a must,
// no gc log rotation when log file not supplied or // no gc log rotation when log file not supplied or
// NumberOfGCLogFiles is 0, or GCLogFileSize is 0 // NumberOfGCLogFiles is 0
void check_gclog_consistency() { void check_gclog_consistency() {
if (UseGCLogFileRotation) { if (UseGCLogFileRotation) {
if ((Arguments::gc_log_filename() == NULL) || if ((Arguments::gc_log_filename() == NULL) || (NumberOfGCLogFiles == 0)) {
(NumberOfGCLogFiles == 0) ||
(GCLogFileSize == 0)) {
jio_fprintf(defaultStream::output_stream(), 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" "To enable GC log rotation, use -Xloggc:<filename> -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=<num_of_files>\n"
"where num_of_file > 0 and num_of_size > 0\n" "where num_of_file > 0\n"
"GC log rotation is turned off\n"); "GC log rotation is turned off\n");
UseGCLogFileRotation = false; UseGCLogFileRotation = false;
} }
} }
if (UseGCLogFileRotation && GCLogFileSize < 8*K) { if (UseGCLogFileRotation && (GCLogFileSize != 0) && (GCLogFileSize < 8*K)) {
FLAG_SET_CMDLINE(uintx, GCLogFileSize, 8*K); FLAG_SET_CMDLINE(uintx, GCLogFileSize, 8*K);
jio_fprintf(defaultStream::output_stream(), jio_fprintf(defaultStream::output_stream(),
"GCLogFileSize changed to minimum 8K\n"); "GCLogFileSize changed to minimum 8K\n");
} }
} }
......
...@@ -2422,9 +2422,9 @@ class CommandLineFlags { ...@@ -2422,9 +2422,9 @@ class CommandLineFlags {
"Number of gclog files in rotation " \ "Number of gclog files in rotation " \
"(default: 0, no rotation)") \ "(default: 0, no rotation)") \
\ \
product(uintx, GCLogFileSize, 0, \ product(uintx, GCLogFileSize, 8*K, \
"GC log file size (default: 0 bytes, no rotation). " \ "GC log file size, requires UseGCLogFileRotation. " \
"It requires UseGCLogFileRotation") \ "Set to 0 to only trigger rotation via jcmd") \
\ \
/* JVMTI heap profiling */ \ /* JVMTI heap profiling */ \
\ \
......
...@@ -535,7 +535,7 @@ void SafepointSynchronize::do_cleanup_tasks() { ...@@ -535,7 +535,7 @@ void SafepointSynchronize::do_cleanup_tasks() {
// rotate log files? // rotate log files?
if (UseGCLogFileRotation) { if (UseGCLogFileRotation) {
gclog_or_tty->rotate_log(); gclog_or_tty->rotate_log(false);
} }
if (MemTracker::is_on()) { if (MemTracker::is_on()) {
......
...@@ -94,6 +94,7 @@ ...@@ -94,6 +94,7 @@
template(JFRCheckpoint) \ template(JFRCheckpoint) \
template(Exit) \ template(Exit) \
template(LinuxDllLoad) \ template(LinuxDllLoad) \
template(RotateGCLog) \
class VM_Operation: public CHeapObj<mtInternal> { class VM_Operation: public CHeapObj<mtInternal> {
public: public:
...@@ -397,4 +398,15 @@ class VM_Exit: public VM_Operation { ...@@ -397,4 +398,15 @@ class VM_Exit: public VM_Operation {
void doit(); 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 #endif // SHARE_VM_RUNTIME_VM_OPERATIONS_HPP
...@@ -53,6 +53,7 @@ void DCmdRegistrant::register_dcmds(){ ...@@ -53,6 +53,7 @@ void DCmdRegistrant::register_dcmds(){
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassStatsDCmd>(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassStatsDCmd>(full_export, true, false));
#endif // INCLUDE_SERVICES #endif // INCLUDE_SERVICES
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ThreadDumpDCmd>(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ThreadDumpDCmd>(full_export, true, false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<RotateGCLogDCmd>(full_export, true, false));
// Enhanced JMX Agent Support // Enhanced JMX Agent Support
// These commands won't be exported via the DiagnosticCommandMBean until an // These commands won't be exported via the DiagnosticCommandMBean until an
...@@ -650,3 +651,11 @@ void JMXStopRemoteDCmd::execute(DCmdSource source, TRAPS) { ...@@ -650,3 +651,11 @@ void JMXStopRemoteDCmd::execute(DCmdSource source, TRAPS) {
JavaCalls::call_static(&result, ik, vmSymbols::stopRemoteAgent_name(), vmSymbols::void_method_signature(), CHECK); 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: ...@@ -360,4 +360,21 @@ public:
virtual void execute(DCmdSource source, TRAPS); 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 #endif // SHARE_VM_SERVICES_DIAGNOSTICCOMMAND_HPP
...@@ -662,13 +662,13 @@ void gcLogFileStream::write(const char* s, size_t len) { ...@@ -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 // 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 // concurrent GC threads to run parallel with VMThread at safepoint, write and rotate_log
// must be synchronized. // must be synchronized.
void gcLogFileStream::rotate_log() { void gcLogFileStream::rotate_log(bool force, outputStream* out) {
char time_msg[FILENAMEBUFLEN]; char time_msg[FILENAMEBUFLEN];
char time_str[EXTRACHARLEN]; char time_str[EXTRACHARLEN];
char current_file_name[FILENAMEBUFLEN]; char current_file_name[FILENAMEBUFLEN];
char renamed_file_name[FILENAMEBUFLEN]; char renamed_file_name[FILENAMEBUFLEN];
if (_bytes_written < (jlong)GCLogFileSize) { if (!should_rotate(force)) {
return; return;
} }
...@@ -685,6 +685,11 @@ void gcLogFileStream::rotate_log() { ...@@ -685,6 +685,11 @@ void gcLogFileStream::rotate_log() {
jio_snprintf(time_msg, sizeof(time_msg), "File %s rotated at %s\n", 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))); _file_name, os::local_time_string((char *)time_str, sizeof(time_str)));
write(time_msg, strlen(time_msg)); write(time_msg, strlen(time_msg));
if (out != NULL) {
out->print(time_msg);
}
dump_loggc_header(); dump_loggc_header();
return; return;
} }
...@@ -706,12 +711,18 @@ void gcLogFileStream::rotate_log() { ...@@ -706,12 +711,18 @@ void gcLogFileStream::rotate_log() {
_file_name, _cur_file_num); _file_name, _cur_file_num);
jio_snprintf(current_file_name, filename_len + EXTRACHARLEN, "%s.%d" CURRENTAPPX, jio_snprintf(current_file_name, filename_len + EXTRACHARLEN, "%s.%d" CURRENTAPPX,
_file_name, _cur_file_num); _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."
os::local_time_string((char *)time_str, sizeof(time_str)), : "GC log file has reached the maximum size.";
renamed_file_name); jio_snprintf(time_msg, sizeof(time_msg), "%s %s Saved as %s\n",
os::local_time_string((char *)time_str, sizeof(time_str)),
msg, renamed_file_name);
write(time_msg, strlen(time_msg)); write(time_msg, strlen(time_msg));
if (out != NULL) {
out->print(time_msg);
}
fclose(_file); fclose(_file);
_file = NULL; _file = NULL;
...@@ -752,6 +763,11 @@ void gcLogFileStream::rotate_log() { ...@@ -752,6 +763,11 @@ void gcLogFileStream::rotate_log() {
os::local_time_string((char *)time_str, sizeof(time_str)), os::local_time_string((char *)time_str, sizeof(time_str)),
current_file_name); current_file_name);
write(time_msg, strlen(time_msg)); write(time_msg, strlen(time_msg));
if (out != NULL) {
out->print(time_msg);
}
dump_loggc_header(); dump_loggc_header();
// remove the existing file // remove the existing file
if (access(current_file_name, F_OK) == 0) { if (access(current_file_name, F_OK) == 0) {
......
...@@ -115,7 +115,7 @@ class outputStream : public ResourceObj { ...@@ -115,7 +115,7 @@ class outputStream : public ResourceObj {
// flushing // flushing
virtual void flush() {} virtual void flush() {}
virtual void write(const char* str, size_t len) = 0; 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 virtual ~outputStream() {} // close properly on deletion
void dec_cr() { dec(); cr(); } void dec_cr() { dec(); cr(); }
...@@ -240,8 +240,15 @@ class gcLogFileStream : public fileStream { ...@@ -240,8 +240,15 @@ class gcLogFileStream : public fileStream {
gcLogFileStream(const char* file_name); gcLogFileStream(const char* file_name);
~gcLogFileStream(); ~gcLogFileStream();
virtual void write(const char* c, size_t len); 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(); 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 #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.
先完成此消息的编辑!
想要评论请 注册