Hi, I'm using "logrotate" tool on RHEL for various log rotation. Now, HotSpot has gclog rotation function for log size base. However, I need to rotate gc log synchronizing with logrotate tool.
So, I've made a patch for executing gclog rotation from external tool. * Changes in HotSpot (hotspot.patch): * gclog rotation request is received via AttachListener. * logrotation function ( rotatingFileStream::rotate_log() ) has 1 parameter. It's determined that gclog rotation is forced or not. * HotSpot allows "GCLogFileSize == 0" . Because we can rotate gclog via external tool. * Changes in JDK (jdk.patch): * gclog rotation is invoked via "jinfo" command with "-rotategclog" option. * With "-rotategclog -force" option, gclog is rotated mandatorily. * "jinfo" is executed "rotategclog" command in AttachListener on target JVM. I've attached these patch in this email. Please check it. I would like to contribute this patch, and I hope to apply this patch to JDK 6 / 7 / 8. Please cooperate. Best regards, Yasumasa
diff -r fc569517f3cf src/share/classes/sun/tools/attach/HotSpotVirtualMachine.java --- a/src/share/classes/sun/tools/attach/HotSpotVirtualMachine.java Mon Sep 05 23:58:19 2011 -0700 +++ b/src/share/classes/sun/tools/attach/HotSpotVirtualMachine.java Fri Sep 09 14:45:26 2011 +0900 @@ -195,6 +195,12 @@ return executeCommand("printflag", name); } + // invoke gclog rotation + public InputStream rotateGCLog(String option) throws IOException { + return executeCommand("rotategclog", option); + + } + // -- Supporting methods diff -r fc569517f3cf src/share/classes/sun/tools/jinfo/JInfo.java --- a/src/share/classes/sun/tools/jinfo/JInfo.java Mon Sep 05 23:58:19 2011 -0700 +++ b/src/share/classes/sun/tools/jinfo/JInfo.java Fri Sep 09 14:45:26 2011 +0900 @@ -58,7 +58,7 @@ if (args.length != 2 && args.length != 3) { usage(); } - } else if (arg1.equals("-flag")) { + } else if (arg1.equals("-flag") || arg1.equals("-rotategclog")) { // do not use SA, use attach-on-demand useSA = false; } else { @@ -70,10 +70,15 @@ if (useSA) { runTool(args); } else { - if (args.length == 3) { + if (arg1.equals("-flag")) { String pid = args[2]; String option = args[1]; flag(pid, option); + } else if (arg1.equals("-rotategclog")) { + if(args.length == 2) // no option + rotategclog(args[1], null); + else // "-force" option + rotategclog(args[2], args[1]); } else { usage(); } @@ -142,6 +147,15 @@ drain(vm, in); } + private static void rotategclog(String pid, String option) throws IOException { + VirtualMachine vm = attach(pid); + InputStream in; + + in = ((HotSpotVirtualMachine)vm).rotateGCLog(option); + + drain(vm, in); + } + // Attach to <pid>, exiting if we fail to attach private static VirtualMachine attach(String pid) { try { @@ -195,6 +209,7 @@ System.out.println(" -flag [+|-]<name> to enable or disable the named VM flag"); System.out.println(" -flag <name>=<value> to set the named VM flag to the given value"); System.out.println(" -flags to print VM flags"); + System.out.println(" -rotategclog [-force] to rotate gclog"); System.out.println(" -sysprops to print Java system properties"); System.out.println(" <no option> to print both of the above"); System.out.println(" -h | -help to print this help message"); @@ -206,6 +221,7 @@ System.out.println(" -flag <name> to print the value of the named VM flag"); System.out.println(" -flag [+|-]<name> to enable or disable the named VM flag"); System.out.println(" -flag <name>=<value> to set the named VM flag to the given value"); + System.out.println(" -rotategclog [-force] to rotate gclog"); System.out.println(" -h | -help to print this help message"); }
diff -r 0fa3ace511fe src/share/vm/runtime/arguments.cpp --- a/src/share/vm/runtime/arguments.cpp Thu Sep 01 13:54:24 2011 -0700 +++ b/src/share/vm/runtime/arguments.cpp Fri Sep 09 15:45:32 2011 +0900 @@ -1682,18 +1682,16 @@ // NumberOfGCLogFiles is 0, or GCLogFileSize 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>\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"); UseGCLogFileRotation = false; } } - if (UseGCLogFileRotation && GCLogFileSize < 8*K) { + if (UseGCLogFileRotation && !FLAG_IS_DEFAULT(GCLogFileSize) && (GCLogFileSize < 8*K)) { FLAG_SET_CMDLINE(uintx, GCLogFileSize, 8*K); jio_fprintf(defaultStream::output_stream(), "GCLogFileSize changed to minimum 8K\n"); diff -r 0fa3ace511fe src/share/vm/runtime/safepoint.cpp --- a/src/share/vm/runtime/safepoint.cpp Thu Sep 01 13:54:24 2011 -0700 +++ b/src/share/vm/runtime/safepoint.cpp Fri Sep 09 15:45:32 2011 +0900 @@ -514,7 +514,7 @@ // rotate log files? if (UseGCLogFileRotation) { - gclog_or_tty->rotate_log(); + gclog_or_tty->rotate_log(false); } } diff -r 0fa3ace511fe src/share/vm/runtime/vm_operations.hpp --- a/src/share/vm/runtime/vm_operations.hpp Thu Sep 01 13:54:24 2011 -0700 +++ b/src/share/vm/runtime/vm_operations.hpp Fri Sep 09 15:45:32 2011 +0900 @@ -94,6 +94,7 @@ template(HeapIterateOperation) \ template(ReportJavaOutOfMemory) \ template(Exit) \ + template(RotateGCLog) \ class VM_Operation: public CHeapObj { public: @@ -405,4 +406,17 @@ void doit(); }; + +class VM_RotateGCLog: public VM_Operation { + + private: + bool _isForce; + + public: + VM_RotateGCLog(bool isForce) { _isForce = isForce; } + VMOp_Type type() const { return VMOp_RotateGCLog; } + void doit() { gclog_or_tty->rotate_log(_isForce); } + +}; + #endif // SHARE_VM_RUNTIME_VM_OPERATIONS_HPP diff -r 0fa3ace511fe src/share/vm/services/attachListener.cpp --- a/src/share/vm/services/attachListener.cpp Thu Sep 01 13:54:24 2011 -0700 +++ b/src/share/vm/services/attachListener.cpp Fri Sep 09 15:45:32 2011 +0900 @@ -351,6 +351,35 @@ return JNI_OK; } +// Implementation of "rotategclog" command +// +// Input arguments :- +// arg0: "-force" +static jint rotate_gclog(AttachOperation* op, outputStream* out) { + const char* arg0 = op->arg(0); + bool isForce = false; + + if(arg0 != NULL){ + if(strcmp(arg0, "-force") == 0){ + isForce = true; + } + else if(arg0[0] != '\0'){ + out->print_cr("Unknown option: %s", arg0); + return JNI_ERR; + } + } + + if(!UseGCLogFileRotation){ + out->print_cr("Target VM is not supported gclog file rotation."); + return JNI_ERR; + } + + VM_RotateGCLog rotateop(isForce); + VMThread::execute(&rotateop); + + return JNI_OK; +} + // Table to map operation names to functions. // names must be of length <= AttachOperation::name_length_max @@ -366,6 +395,7 @@ { "inspectheap", heap_inspection }, { "setflag", set_flag }, { "printflag", print_flag }, + { "rotategclog", rotate_gclog }, { NULL, NULL } }; diff -r 0fa3ace511fe src/share/vm/utilities/ostream.cpp --- a/src/share/vm/utilities/ostream.cpp Thu Sep 01 13:54:24 2011 -0700 +++ b/src/share/vm/utilities/ostream.cpp Fri Sep 09 15:45:32 2011 +0900 @@ -421,8 +421,13 @@ // 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 rotatingFileStream::rotate_log() { - if (_bytes_writen < (jlong)GCLogFileSize) return; +void rotatingFileStream::rotate_log(bool isForce) { + + if(!isForce && + ((GCLogFileSize > 0) && (_bytes_writen < (jlong)GCLogFileSize))){ + return; + } + #ifdef ASSERT Thread *thread = Thread::current(); assert(thread == NULL || diff -r 0fa3ace511fe src/share/vm/utilities/ostream.hpp --- a/src/share/vm/utilities/ostream.hpp Thu Sep 01 13:54:24 2011 -0700 +++ b/src/share/vm/utilities/ostream.hpp Fri Sep 09 15:45:32 2011 +0900 @@ -110,7 +110,7 @@ // 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 isForce) {} // GC log rotation virtual ~outputStream() {} // close properly on deletion void dec_cr() { dec(); cr(); } @@ -223,7 +223,7 @@ rotatingFileStream(FILE* file) : fileStream(file) {} ~rotatingFileStream(); virtual void write(const char* c, size_t len); - virtual void rotate_log(); + virtual void rotate_log(bool isForce); }; void ostream_init();