6941923: RFE: Handling large log files produced by long running Java Applications

Yasumasa Suenaga suenaga.yasumasa at oss.ntt.co.jp
Mon Sep 12 01:18:36 UTC 2011


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

-------------- next part --------------
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");
         }
 
-------------- next part --------------
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();


More information about the hotspot-gc-dev mailing list