7090324: gclog rotation via external tool

Mon, 31 Mar 2014 13:09:35 -0700

author
minqi
date
Mon, 31 Mar 2014 13:09:35 -0700
changeset 6535
f42c10a3d4b1
parent 6534
d5818eeedb40
child 6536
8a84bedf7173

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

src/share/vm/runtime/arguments.cpp file | annotate | diff | comparison | revisions
src/share/vm/runtime/globals.hpp file | annotate | diff | comparison | revisions
src/share/vm/runtime/safepoint.cpp file | annotate | diff | comparison | revisions
src/share/vm/runtime/vm_operations.hpp file | annotate | diff | comparison | revisions
src/share/vm/services/diagnosticCommand.cpp file | annotate | diff | comparison | revisions
src/share/vm/services/diagnosticCommand.hpp file | annotate | diff | comparison | revisions
src/share/vm/utilities/ostream.cpp file | annotate | diff | comparison | revisions
src/share/vm/utilities/ostream.hpp file | annotate | diff | comparison | revisions
test/gc/TestGCLogRotationViaJcmd.java file | annotate | diff | comparison | revisions
     1.1 --- a/src/share/vm/runtime/arguments.cpp	Fri Mar 28 15:29:23 2014 -0700
     1.2 +++ b/src/share/vm/runtime/arguments.cpp	Mon Mar 31 13:09:35 2014 -0700
     1.3 @@ -1880,24 +1880,22 @@
     1.4  // check if do gclog rotation
     1.5  // +UseGCLogFileRotation is a must,
     1.6  // no gc log rotation when log file not supplied or
     1.7 -// NumberOfGCLogFiles is 0, or GCLogFileSize is 0
     1.8 +// NumberOfGCLogFiles is 0
     1.9  void check_gclog_consistency() {
    1.10    if (UseGCLogFileRotation) {
    1.11 -    if ((Arguments::gc_log_filename() == NULL) ||
    1.12 -        (NumberOfGCLogFiles == 0)  ||
    1.13 -        (GCLogFileSize == 0)) {
    1.14 +    if ((Arguments::gc_log_filename() == NULL) || (NumberOfGCLogFiles == 0)) {
    1.15        jio_fprintf(defaultStream::output_stream(),
    1.16 -                  "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"
    1.17 -                  "where num_of_file > 0 and num_of_size > 0\n"
    1.18 +                  "To enable GC log rotation, use -Xloggc:<filename> -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=<num_of_files>\n"
    1.19 +                  "where num_of_file > 0\n"
    1.20                    "GC log rotation is turned off\n");
    1.21        UseGCLogFileRotation = false;
    1.22      }
    1.23    }
    1.24  
    1.25 -  if (UseGCLogFileRotation && GCLogFileSize < 8*K) {
    1.26 -        FLAG_SET_CMDLINE(uintx, GCLogFileSize, 8*K);
    1.27 -        jio_fprintf(defaultStream::output_stream(),
    1.28 -                    "GCLogFileSize changed to minimum 8K\n");
    1.29 +  if (UseGCLogFileRotation && (GCLogFileSize != 0) && (GCLogFileSize < 8*K)) {
    1.30 +    FLAG_SET_CMDLINE(uintx, GCLogFileSize, 8*K);
    1.31 +    jio_fprintf(defaultStream::output_stream(),
    1.32 +                "GCLogFileSize changed to minimum 8K\n");
    1.33    }
    1.34  }
    1.35  
     2.1 --- a/src/share/vm/runtime/globals.hpp	Fri Mar 28 15:29:23 2014 -0700
     2.2 +++ b/src/share/vm/runtime/globals.hpp	Mon Mar 31 13:09:35 2014 -0700
     2.3 @@ -2422,9 +2422,9 @@
     2.4            "Number of gclog files in rotation "                              \
     2.5            "(default: 0, no rotation)")                                      \
     2.6                                                                              \
     2.7 -  product(uintx, GCLogFileSize, 0,                                          \
     2.8 -          "GC log file size (default: 0 bytes, no rotation). "              \
     2.9 -          "It requires UseGCLogFileRotation")                               \
    2.10 +  product(uintx, GCLogFileSize, 8*K,                                        \
    2.11 +          "GC log file size, requires UseGCLogFileRotation. "               \
    2.12 +          "Set to 0 to only trigger rotation via jcmd")                     \
    2.13                                                                              \
    2.14    /* JVMTI heap profiling */                                                \
    2.15                                                                              \
     3.1 --- a/src/share/vm/runtime/safepoint.cpp	Fri Mar 28 15:29:23 2014 -0700
     3.2 +++ b/src/share/vm/runtime/safepoint.cpp	Mon Mar 31 13:09:35 2014 -0700
     3.3 @@ -535,7 +535,7 @@
     3.4  
     3.5    // rotate log files?
     3.6    if (UseGCLogFileRotation) {
     3.7 -    gclog_or_tty->rotate_log();
     3.8 +    gclog_or_tty->rotate_log(false);
     3.9    }
    3.10  
    3.11    if (MemTracker::is_on()) {
     4.1 --- a/src/share/vm/runtime/vm_operations.hpp	Fri Mar 28 15:29:23 2014 -0700
     4.2 +++ b/src/share/vm/runtime/vm_operations.hpp	Mon Mar 31 13:09:35 2014 -0700
     4.3 @@ -94,6 +94,7 @@
     4.4    template(JFRCheckpoint)                         \
     4.5    template(Exit)                                  \
     4.6    template(LinuxDllLoad)                          \
     4.7 +  template(RotateGCLog)                           \
     4.8  
     4.9  class VM_Operation: public CHeapObj<mtInternal> {
    4.10   public:
    4.11 @@ -397,4 +398,15 @@
    4.12    void doit();
    4.13  };
    4.14  
    4.15 +
    4.16 +class VM_RotateGCLog: public VM_Operation {
    4.17 + private:
    4.18 +  outputStream* _out;
    4.19 +
    4.20 + public:
    4.21 +  VM_RotateGCLog(outputStream* st) : _out(st) {}
    4.22 +  VMOp_Type type() const { return VMOp_RotateGCLog; }
    4.23 +  void doit() { gclog_or_tty->rotate_log(true, _out); }
    4.24 +};
    4.25 +
    4.26  #endif // SHARE_VM_RUNTIME_VM_OPERATIONS_HPP
     5.1 --- a/src/share/vm/services/diagnosticCommand.cpp	Fri Mar 28 15:29:23 2014 -0700
     5.2 +++ b/src/share/vm/services/diagnosticCommand.cpp	Mon Mar 31 13:09:35 2014 -0700
     5.3 @@ -53,6 +53,7 @@
     5.4    DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassStatsDCmd>(full_export, true, false));
     5.5  #endif // INCLUDE_SERVICES
     5.6    DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ThreadDumpDCmd>(full_export, true, false));
     5.7 +  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<RotateGCLogDCmd>(full_export, true, false));
     5.8  
     5.9    // Enhanced JMX Agent Support
    5.10    // These commands won't be exported via the DiagnosticCommandMBean until an
    5.11 @@ -650,3 +651,11 @@
    5.12      JavaCalls::call_static(&result, ik, vmSymbols::stopRemoteAgent_name(), vmSymbols::void_method_signature(), CHECK);
    5.13  }
    5.14  
    5.15 +void RotateGCLogDCmd::execute(DCmdSource source, TRAPS) {
    5.16 +  if (UseGCLogFileRotation) {
    5.17 +    VM_RotateGCLog rotateop(output());
    5.18 +    VMThread::execute(&rotateop);
    5.19 +  } else {
    5.20 +    output()->print_cr("Target VM does not support GC log file rotation.");
    5.21 +  }
    5.22 +}
     6.1 --- a/src/share/vm/services/diagnosticCommand.hpp	Fri Mar 28 15:29:23 2014 -0700
     6.2 +++ b/src/share/vm/services/diagnosticCommand.hpp	Mon Mar 31 13:09:35 2014 -0700
     6.3 @@ -360,4 +360,21 @@
     6.4    virtual void execute(DCmdSource source, TRAPS);
     6.5  };
     6.6  
     6.7 +class RotateGCLogDCmd : public DCmd {
     6.8 +public:
     6.9 +  RotateGCLogDCmd(outputStream* output, bool heap) : DCmd(output, heap) {}
    6.10 +  static const char* name() { return "GC.rotate_log"; }
    6.11 +  static const char* description() {
    6.12 +    return "Force the GC log file to be rotated.";
    6.13 +  }
    6.14 +  static const char* impact() { return "Low"; }
    6.15 +  virtual void execute(DCmdSource source, TRAPS);
    6.16 +  static int num_arguments() { return 0; }
    6.17 +  static const JavaPermission permission() {
    6.18 +    JavaPermission p = {"java.lang.management.ManagementPermission",
    6.19 +                        "control", NULL};
    6.20 +    return p;
    6.21 +  }
    6.22 +};
    6.23 +
    6.24  #endif // SHARE_VM_SERVICES_DIAGNOSTICCOMMAND_HPP
     7.1 --- a/src/share/vm/utilities/ostream.cpp	Fri Mar 28 15:29:23 2014 -0700
     7.2 +++ b/src/share/vm/utilities/ostream.cpp	Mon Mar 31 13:09:35 2014 -0700
     7.3 @@ -662,13 +662,13 @@
     7.4  // write to gc log file at safepoint. If in future, changes made for mutator threads or
     7.5  // concurrent GC threads to run parallel with VMThread at safepoint, write and rotate_log
     7.6  // must be synchronized.
     7.7 -void gcLogFileStream::rotate_log() {
     7.8 +void gcLogFileStream::rotate_log(bool force, outputStream* out) {
     7.9    char time_msg[FILENAMEBUFLEN];
    7.10    char time_str[EXTRACHARLEN];
    7.11    char current_file_name[FILENAMEBUFLEN];
    7.12    char renamed_file_name[FILENAMEBUFLEN];
    7.13  
    7.14 -  if (_bytes_written < (jlong)GCLogFileSize) {
    7.15 +  if (!should_rotate(force)) {
    7.16      return;
    7.17    }
    7.18  
    7.19 @@ -685,6 +685,11 @@
    7.20      jio_snprintf(time_msg, sizeof(time_msg), "File  %s rotated at %s\n",
    7.21                   _file_name, os::local_time_string((char *)time_str, sizeof(time_str)));
    7.22      write(time_msg, strlen(time_msg));
    7.23 +
    7.24 +    if (out != NULL) {
    7.25 +      out->print(time_msg);
    7.26 +    }
    7.27 +
    7.28      dump_loggc_header();
    7.29      return;
    7.30    }
    7.31 @@ -706,12 +711,18 @@
    7.32                   _file_name, _cur_file_num);
    7.33      jio_snprintf(current_file_name, filename_len + EXTRACHARLEN, "%s.%d" CURRENTAPPX,
    7.34                   _file_name, _cur_file_num);
    7.35 -    jio_snprintf(time_msg, sizeof(time_msg), "%s GC log file has reached the"
    7.36 -                           " maximum size. Saved as %s\n",
    7.37 -                           os::local_time_string((char *)time_str, sizeof(time_str)),
    7.38 -                           renamed_file_name);
    7.39 +
    7.40 +    const char* msg = force ? "GC log rotation request has been received."
    7.41 +                            : "GC log file has reached the maximum size.";
    7.42 +    jio_snprintf(time_msg, sizeof(time_msg), "%s %s Saved as %s\n",
    7.43 +                     os::local_time_string((char *)time_str, sizeof(time_str)),
    7.44 +                                                         msg, renamed_file_name);
    7.45      write(time_msg, strlen(time_msg));
    7.46  
    7.47 +    if (out != NULL) {
    7.48 +      out->print(time_msg);
    7.49 +    }
    7.50 +
    7.51      fclose(_file);
    7.52      _file = NULL;
    7.53  
    7.54 @@ -752,6 +763,11 @@
    7.55                             os::local_time_string((char *)time_str, sizeof(time_str)),
    7.56                             current_file_name);
    7.57      write(time_msg, strlen(time_msg));
    7.58 +
    7.59 +    if (out != NULL) {
    7.60 +      out->print(time_msg);
    7.61 +    }
    7.62 +
    7.63      dump_loggc_header();
    7.64      // remove the existing file
    7.65      if (access(current_file_name, F_OK) == 0) {
     8.1 --- a/src/share/vm/utilities/ostream.hpp	Fri Mar 28 15:29:23 2014 -0700
     8.2 +++ b/src/share/vm/utilities/ostream.hpp	Mon Mar 31 13:09:35 2014 -0700
     8.3 @@ -115,7 +115,7 @@
     8.4     // flushing
     8.5     virtual void flush() {}
     8.6     virtual void write(const char* str, size_t len) = 0;
     8.7 -   virtual void rotate_log() {} // GC log rotation
     8.8 +   virtual void rotate_log(bool force, outputStream* out = NULL) {} // GC log rotation
     8.9     virtual ~outputStream() {}   // close properly on deletion
    8.10  
    8.11     void dec_cr() { dec(); cr(); }
    8.12 @@ -240,8 +240,15 @@
    8.13    gcLogFileStream(const char* file_name);
    8.14    ~gcLogFileStream();
    8.15    virtual void write(const char* c, size_t len);
    8.16 -  virtual void rotate_log();
    8.17 +  virtual void rotate_log(bool force, outputStream* out = NULL);
    8.18    void dump_loggc_header();
    8.19 +
    8.20 +  /* If "force" sets true, force log file rotation from outside JVM */
    8.21 +  bool should_rotate(bool force) {
    8.22 +    return force ||
    8.23 +             ((GCLogFileSize != 0) && ((uintx)_bytes_written >= GCLogFileSize));
    8.24 +  }
    8.25 +
    8.26  };
    8.27  
    8.28  #ifndef PRODUCT
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/test/gc/TestGCLogRotationViaJcmd.java	Mon Mar 31 13:09:35 2014 -0700
     9.3 @@ -0,0 +1,77 @@
     9.4 +/*
     9.5 + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
     9.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     9.7 + *
     9.8 + * This code is free software; you can redistribute it and/or modify it
     9.9 + * under the terms of the GNU General Public License version 2 only, as
    9.10 + * published by the Free Software Foundation.
    9.11 + *
    9.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    9.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    9.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    9.15 + * version 2 for more details (a copy is included in the LICENSE file that
    9.16 + * accompanied this code).
    9.17 + *
    9.18 + * You should have received a copy of the GNU General Public License version
    9.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    9.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    9.21 + *
    9.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    9.23 + * or visit www.oracle.com if you need additional information or have any
    9.24 + * questions.
    9.25 + */
    9.26 +
    9.27 +/*
    9.28 + * @test TestGCLogRotationViaJcmd.java
    9.29 + * @bug 7090324
    9.30 + * @summary test for gc log rotation via jcmd
    9.31 + * @library /testlibrary
    9.32 + * @run main/othervm -Xloggc:test.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=3 TestGCLogRotationViaJcmd
    9.33 + *
    9.34 + */
    9.35 +import com.oracle.java.testlibrary.*;
    9.36 +import java.io.File;
    9.37 +import java.io.FilenameFilter;
    9.38 +
    9.39 +public class TestGCLogRotationViaJcmd {
    9.40 +
    9.41 +    static final File currentDirectory = new File(".");
    9.42 +    static final String LOG_FILE_NAME = "test.log";
    9.43 +    static final int NUM_LOGS = 3;
    9.44 +
    9.45 +    static FilenameFilter logFilter = new FilenameFilter() {
    9.46 +        @Override
    9.47 +        public boolean accept(File dir, String name) {
    9.48 +            return name.startsWith(LOG_FILE_NAME);
    9.49 +        }
    9.50 +    };
    9.51 +
    9.52 +    public static void main(String[] args) throws Exception {
    9.53 +        // Grab the pid from the current java process
    9.54 +        String pid = Integer.toString(ProcessTools.getProcessId());
    9.55 +
    9.56 +        // Create a JDKToolLauncher
    9.57 +        JDKToolLauncher jcmd = JDKToolLauncher.create("jcmd")
    9.58 +                                              .addToolArg(pid)
    9.59 +                                              .addToolArg("GC.rotate_log");
    9.60 +
    9.61 +        for (int times = 1; times < NUM_LOGS; times++) {
    9.62 +            // Run jcmd <pid> GC.rotate_log
    9.63 +            ProcessBuilder pb = new ProcessBuilder(jcmd.getCommand());
    9.64 +
    9.65 +            // Make sure we didn't crash
    9.66 +            OutputAnalyzer output = new OutputAnalyzer(pb.start());
    9.67 +            output.shouldHaveExitValue(0);
    9.68 +        }
    9.69 +
    9.70 +        // GC log check
    9.71 +        File[] logs = currentDirectory.listFiles(logFilter);
    9.72 +        if (logs.length != NUM_LOGS) {
    9.73 +            throw new Error("There are only " + logs.length
    9.74 +                                              + " logs instead " + NUM_LOGS);
    9.75 +        }
    9.76 +
    9.77 +    }
    9.78 +
    9.79 +}
    9.80 +

mercurial