Hi all, We are using "logrotate" tool on RHEL for various log rotation. Current HotSpot has gclog rotation function for log size base, however I need to rotate gc log synchronizing with logrotate tool.
So I've created RFE as "JDK-7090324: gclog rotation via external tool" . And Sr. Engineering Manager in Oracle said he use the essence of my patch in one of the jcmd subcommands. http://mail.openjdk.java.net/pipermail/hotspot-gc-dev/2011-September/003274.html 2 years ago, I posted a patch for this RFE. But this patch is too old to apply for current HotSpot. In last month, a similar discussion was appeared in ML. So I think it's time to discuss this RFE. http://mail.openjdk.java.net/pipermail/hotspot-gc-dev/2013-August/008029.html Please cooperate. Best regards, Yasumasa
diff -r ae2edb3df7fb src/share/vm/runtime/arguments.cpp --- a/src/share/vm/runtime/arguments.cpp Sun Sep 22 18:07:43 2013 +0200 +++ b/src/share/vm/runtime/arguments.cpp Sun Sep 29 23:11:37 2013 +0900 @@ -1869,18 +1869,17 @@ // 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>[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 && !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 ae2edb3df7fb src/share/vm/runtime/safepoint.cpp --- a/src/share/vm/runtime/safepoint.cpp Sun Sep 22 18:07:43 2013 +0200 +++ b/src/share/vm/runtime/safepoint.cpp Sun Sep 29 23:11:37 2013 +0900 @@ -535,7 +535,7 @@ // rotate log files? if (UseGCLogFileRotation) { - gclog_or_tty->rotate_log(); + gclog_or_tty->rotate_log(false); } if (MemTracker::is_on()) { diff -r ae2edb3df7fb src/share/vm/runtime/vm_operations.hpp --- a/src/share/vm/runtime/vm_operations.hpp Sun Sep 22 18:07:43 2013 +0200 +++ b/src/share/vm/runtime/vm_operations.hpp Sun Sep 29 23:11:37 2013 +0900 @@ -95,6 +95,7 @@ template(JFRCheckpoint) \ template(Exit) \ template(LinuxDllLoad) \ + template(RotateGCLog) \ class VM_Operation: public CHeapObj<mtInternal> { public: @@ -408,4 +409,17 @@ void doit(); }; + +class VM_RotateGCLog: public VM_Operation{ + + private: + bool _is_force; + + public: + VM_RotateGCLog(bool is_force) { _is_force = is_force; } + VMOp_Type type() const { return VMOp_RotateGCLog; } + void doit() { gclog_or_tty->rotate_log(_is_force); } + +}; + #endif // SHARE_VM_RUNTIME_VM_OPERATIONS_HPP diff -r ae2edb3df7fb src/share/vm/services/diagnosticCommand.cpp --- a/src/share/vm/services/diagnosticCommand.cpp Sun Sep 22 18:07:43 2013 +0200 +++ b/src/share/vm/services/diagnosticCommand.cpp Sun Sep 29 23:11:37 2013 +0900 @@ -53,6 +53,7 @@ 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 @@ -644,3 +645,35 @@ JavaCalls::call_static(&result, ik, vmSymbols::stopRemoteAgent_name(), vmSymbols::void_method_signature(), CHECK); } + +RotateGCLogDCmd::RotateGCLogDCmd(outputStream* output, bool heap) : + DCmdWithParser(output, heap), + _force("-force", "Force execute GC log rotation.", "BOOLEAN", false, "false") { + _dcmdparser.add_dcmd_option(&_force); +} + +void RotateGCLogDCmd::execute(DCmdSource source, TRAPS) { + + if(UseGCLogFileRotation){ + VM_RotateGCLog rotateop(_force.value()); + VMThread::execute(&rotateop); + } + else{ + output()->print_cr("Target VM is not supported GC log rotation."); + } + +} + +int RotateGCLogDCmd::num_arguments() { + ResourceMark rm; + RotateGCLogDCmd* dcmd = new RotateGCLogDCmd(NULL, false); + + if (dcmd != NULL) { + DCmdMark mark(dcmd); + return dcmd->_dcmdparser.num_arguments(); + } else { + return 0; + } + +} + diff -r ae2edb3df7fb src/share/vm/services/diagnosticCommand.hpp --- a/src/share/vm/services/diagnosticCommand.hpp Sun Sep 22 18:07:43 2013 +0200 +++ b/src/share/vm/services/diagnosticCommand.hpp Sun Sep 29 23:11:37 2013 +0900 @@ -359,4 +359,20 @@ virtual void execute(DCmdSource source, TRAPS); }; + +class RotateGCLogDCmd : public DCmdWithParser { +protected: + DCmdArgument<bool> _force; +public: + RotateGCLogDCmd(outputStream* output, bool heap); + static const char* name() { return "GC.rotate_log"; } + static const char* description() { + return "GC log rotation."; + } + static const char* impact() { return "Low"; } + static int num_arguments(); + virtual void execute(DCmdSource source, TRAPS); +}; + + #endif // SHARE_VM_SERVICES_DIAGNOSTICCOMMAND_HPP diff -r ae2edb3df7fb src/share/vm/utilities/ostream.cpp --- a/src/share/vm/utilities/ostream.cpp Sun Sep 22 18:07:43 2013 +0200 +++ b/src/share/vm/utilities/ostream.cpp Sun Sep 29 23:11:37 2013 +0900 @@ -659,16 +659,26 @@ // 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 is_force) { char time_msg[FILENAMEBUFLEN]; char time_str[EXTRACHARLEN]; char current_file_name[FILENAMEBUFLEN]; char renamed_file_name[FILENAMEBUFLEN]; - if (_bytes_written < (jlong)GCLogFileSize) { - return; + if(!is_force){ /* rotation request is NOT force. */ + + if(GCLogFileSize == 0){ + /* GC log rotation occurs external force trigger ONLY. */ + return; + } + else if(_bytes_written < (jlong)GCLogFileSize){ + /* This case is size-based rotation and not need to rotate log yet. */ + return; + } + } + #ifdef ASSERT Thread *thread = Thread::current(); assert(thread == NULL || @@ -703,10 +713,19 @@ _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" + + if(is_force){ + jio_snprintf(time_msg, sizeof(time_msg), "%s GC log rotating request has received. Saved as %s\n", + os::local_time_string((char *)time_str, sizeof(time_str)), + renamed_file_name); + } + else{ + jio_snprintf(time_msg, sizeof(time_msg), "%s GC log file has reached the" " maximum size. Saved as %s\n", - os::local_time_string((char *)time_str, sizeof(time_str)), + os::local_time_string((char *)time_str, sizeof(time_str)), renamed_file_name); + } + write(time_msg, strlen(time_msg)); fclose(_file); diff -r ae2edb3df7fb src/share/vm/utilities/ostream.hpp --- a/src/share/vm/utilities/ostream.hpp Sun Sep 22 18:07:43 2013 +0200 +++ b/src/share/vm/utilities/ostream.hpp Sun Sep 29 23:11:37 2013 +0900 @@ -115,7 +115,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 is_force) {} // GC log rotation virtual ~outputStream() {} // close properly on deletion void dec_cr() { dec(); cr(); } @@ -240,7 +240,7 @@ gcLogFileStream(const char* file_name); ~gcLogFileStream(); virtual void write(const char* c, size_t len); - virtual void rotate_log(); + virtual void rotate_log(bool is_force); void dump_loggc_header(); };