7164841: Improvements to the GC log file rotation

Mon, 16 Sep 2013 15:35:04 -0700

author
minqi
date
Mon, 16 Sep 2013 15:35:04 -0700
changeset 5683
621eda7235d2
parent 5680
4472884d8b37
child 5684
535973ddf22c

7164841: Improvements to the GC log file rotation
Summary: made changes to easily identify current log file in rotation. Parameterize the input with %t for time replacement in file name.
Reviewed-by: ccheung, tschatzl, tamao, zgu
Contributed-by: yumin.qi@oracle.com

src/share/vm/prims/jni.cpp file | annotate | diff | comparison | revisions
src/share/vm/runtime/arguments.cpp 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
     1.1 --- a/src/share/vm/prims/jni.cpp	Mon Sep 16 12:43:34 2013 -0700
     1.2 +++ b/src/share/vm/prims/jni.cpp	Mon Sep 16 15:35:04 2013 -0700
     1.3 @@ -5037,6 +5037,7 @@
     1.4  #include "gc_implementation/g1/heapRegionRemSet.hpp"
     1.5  #endif
     1.6  #include "utilities/quickSort.hpp"
     1.7 +#include "utilities/ostream.hpp"
     1.8  #if INCLUDE_VM_STRUCTS
     1.9  #include "runtime/vmStructs.hpp"
    1.10  #endif
    1.11 @@ -5060,6 +5061,7 @@
    1.12      run_unit_test(CollectedHeap::test_is_in());
    1.13      run_unit_test(QuickSort::test_quick_sort());
    1.14      run_unit_test(AltHashing::test_alt_hash());
    1.15 +    run_unit_test(test_loggc_filename());
    1.16  #if INCLUDE_VM_STRUCTS
    1.17      run_unit_test(VMStructs::test());
    1.18  #endif
     2.1 --- a/src/share/vm/runtime/arguments.cpp	Mon Sep 16 12:43:34 2013 -0700
     2.2 +++ b/src/share/vm/runtime/arguments.cpp	Mon Sep 16 15:35:04 2013 -0700
     2.3 @@ -1839,7 +1839,7 @@
     2.4          (NumberOfGCLogFiles == 0)  ||
     2.5          (GCLogFileSize == 0)) {
     2.6        jio_fprintf(defaultStream::output_stream(),
     2.7 -                  "To enable GC log rotation, use -Xloggc:<filename> -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=<num_of_files> -XX:GCLogFileSize=<num_of_size>\n"
     2.8 +                  "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"
     2.9                    "where num_of_file > 0 and num_of_size > 0\n"
    2.10                    "GC log rotation is turned off\n");
    2.11        UseGCLogFileRotation = false;
    2.12 @@ -1853,6 +1853,51 @@
    2.13    }
    2.14  }
    2.15  
    2.16 +// This function is called for -Xloggc:<filename>, it can be used
    2.17 +// to check if a given file name(or string) conforms to the following
    2.18 +// specification:
    2.19 +// A valid string only contains "[A-Z][a-z][0-9].-_%[p|t]"
    2.20 +// %p and %t only allowed once. We only limit usage of filename not path
    2.21 +bool is_filename_valid(const char *file_name) {
    2.22 +  const char* p = file_name;
    2.23 +  char file_sep = os::file_separator()[0];
    2.24 +  const char* cp;
    2.25 +  // skip prefix path
    2.26 +  for (cp = file_name; *cp != '\0'; cp++) {
    2.27 +    if (*cp == '/' || *cp == file_sep) {
    2.28 +      p = cp + 1;
    2.29 +    }
    2.30 +  }
    2.31 +
    2.32 +  int count_p = 0;
    2.33 +  int count_t = 0;
    2.34 +  while (*p != '\0') {
    2.35 +    if ((*p >= '0' && *p <= '9') ||
    2.36 +        (*p >= 'A' && *p <= 'Z') ||
    2.37 +        (*p >= 'a' && *p <= 'z') ||
    2.38 +         *p == '-'               ||
    2.39 +         *p == '_'               ||
    2.40 +         *p == '.') {
    2.41 +       p++;
    2.42 +       continue;
    2.43 +    }
    2.44 +    if (*p == '%') {
    2.45 +      if(*(p + 1) == 'p') {
    2.46 +        p += 2;
    2.47 +        count_p ++;
    2.48 +        continue;
    2.49 +      }
    2.50 +      if (*(p + 1) == 't') {
    2.51 +        p += 2;
    2.52 +        count_t ++;
    2.53 +        continue;
    2.54 +      }
    2.55 +    }
    2.56 +    return false;
    2.57 +  }
    2.58 +  return count_p < 2 && count_t < 2;
    2.59 +}
    2.60 +
    2.61  // Check consistency of GC selection
    2.62  bool Arguments::check_gc_consistency() {
    2.63    check_gclog_consistency();
    2.64 @@ -2806,6 +2851,13 @@
    2.65        // ostream_init_log(), when called will use this filename
    2.66        // to initialize a fileStream.
    2.67        _gc_log_filename = strdup(tail);
    2.68 +     if (!is_filename_valid(_gc_log_filename)) {
    2.69 +       jio_fprintf(defaultStream::output_stream(),
    2.70 +                  "Invalid file name for use with -Xloggc: Filename can only contain the "
    2.71 +                  "characters [A-Z][a-z][0-9]-_.%%[p|t] but it has been %s\n"
    2.72 +                  "Note %%p or %%t can only be used once\n", _gc_log_filename);
    2.73 +        return JNI_EINVAL;
    2.74 +      }
    2.75        FLAG_SET_CMDLINE(bool, PrintGC, true);
    2.76        FLAG_SET_CMDLINE(bool, PrintGCTimeStamps, true);
    2.77  
     3.1 --- a/src/share/vm/utilities/ostream.cpp	Mon Sep 16 12:43:34 2013 -0700
     3.2 +++ b/src/share/vm/utilities/ostream.cpp	Mon Sep 16 15:35:04 2013 -0700
     3.3 @@ -342,7 +342,7 @@
     3.4  }
     3.5  
     3.6  char* stringStream::as_string() {
     3.7 -  char* copy = NEW_RESOURCE_ARRAY(char, buffer_pos+1);
     3.8 +  char* copy = NEW_RESOURCE_ARRAY(char, buffer_pos + 1);
     3.9    strncpy(copy, buffer, buffer_pos);
    3.10    copy[buffer_pos] = 0;  // terminating null
    3.11    return copy;
    3.12 @@ -355,14 +355,190 @@
    3.13  outputStream* gclog_or_tty;
    3.14  extern Mutex* tty_lock;
    3.15  
    3.16 +#define EXTRACHARLEN   32
    3.17 +#define CURRENTAPPX    ".current"
    3.18 +#define FILENAMEBUFLEN  1024
    3.19 +// convert YYYY-MM-DD HH:MM:SS to YYYY-MM-DD_HH-MM-SS
    3.20 +char* get_datetime_string(char *buf, size_t len) {
    3.21 +  os::local_time_string(buf, len);
    3.22 +  int i = (int)strlen(buf);
    3.23 +  while (i-- >= 0) {
    3.24 +    if (buf[i] == ' ') buf[i] = '_';
    3.25 +    else if (buf[i] == ':') buf[i] = '-';
    3.26 +  }
    3.27 +  return buf;
    3.28 +}
    3.29 +
    3.30 +static const char* make_log_name_internal(const char* log_name, const char* force_directory,
    3.31 +                                                int pid, const char* tms) {
    3.32 +  const char* basename = log_name;
    3.33 +  char file_sep = os::file_separator()[0];
    3.34 +  const char* cp;
    3.35 +  char  pid_text[32];
    3.36 +
    3.37 +  for (cp = log_name; *cp != '\0'; cp++) {
    3.38 +    if (*cp == '/' || *cp == file_sep) {
    3.39 +      basename = cp + 1;
    3.40 +    }
    3.41 +  }
    3.42 +  const char* nametail = log_name;
    3.43 +  // Compute buffer length
    3.44 +  size_t buffer_length;
    3.45 +  if (force_directory != NULL) {
    3.46 +    buffer_length = strlen(force_directory) + strlen(os::file_separator()) +
    3.47 +                    strlen(basename) + 1;
    3.48 +  } else {
    3.49 +    buffer_length = strlen(log_name) + 1;
    3.50 +  }
    3.51 +
    3.52 +  // const char* star = strchr(basename, '*');
    3.53 +  const char* pts = strstr(basename, "%p");
    3.54 +  int pid_pos = (pts == NULL) ? -1 : (pts - nametail);
    3.55 +
    3.56 +  if (pid_pos >= 0) {
    3.57 +    jio_snprintf(pid_text, sizeof(pid_text), "pid%u", pid);
    3.58 +    buffer_length += strlen(pid_text);
    3.59 +  }
    3.60 +
    3.61 +  pts = strstr(basename, "%t");
    3.62 +  int tms_pos = (pts == NULL) ? -1 : (pts - nametail);
    3.63 +  if (tms_pos >= 0) {
    3.64 +    buffer_length += strlen(tms);
    3.65 +  }
    3.66 +
    3.67 +  // Create big enough buffer.
    3.68 +  char *buf = NEW_C_HEAP_ARRAY(char, buffer_length, mtInternal);
    3.69 +
    3.70 +  strcpy(buf, "");
    3.71 +  if (force_directory != NULL) {
    3.72 +    strcat(buf, force_directory);
    3.73 +    strcat(buf, os::file_separator());
    3.74 +    nametail = basename;       // completely skip directory prefix
    3.75 +  }
    3.76 +
    3.77 +  // who is first, %p or %t?
    3.78 +  int first = -1, second = -1;
    3.79 +  const char *p1st = NULL;
    3.80 +  const char *p2nd = NULL;
    3.81 +
    3.82 +  if (pid_pos >= 0 && tms_pos >= 0) {
    3.83 +    // contains both %p and %t
    3.84 +    if (pid_pos < tms_pos) {
    3.85 +      // case foo%pbar%tmonkey.log
    3.86 +      first  = pid_pos;
    3.87 +      p1st   = pid_text;
    3.88 +      second = tms_pos;
    3.89 +      p2nd   = tms;
    3.90 +    } else {
    3.91 +      // case foo%tbar%pmonkey.log
    3.92 +      first  = tms_pos;
    3.93 +      p1st   = tms;
    3.94 +      second = pid_pos;
    3.95 +      p2nd   = pid_text;
    3.96 +    }
    3.97 +  } else if (pid_pos >= 0) {
    3.98 +    // contains %p only
    3.99 +    first  = pid_pos;
   3.100 +    p1st   = pid_text;
   3.101 +  } else if (tms_pos >= 0) {
   3.102 +    // contains %t only
   3.103 +    first  = tms_pos;
   3.104 +    p1st   = tms;
   3.105 +  }
   3.106 +
   3.107 +  int buf_pos = (int)strlen(buf);
   3.108 +  const char* tail = nametail;
   3.109 +
   3.110 +  if (first >= 0) {
   3.111 +    tail = nametail + first + 2;
   3.112 +    strncpy(&buf[buf_pos], nametail, first);
   3.113 +    strcpy(&buf[buf_pos + first], p1st);
   3.114 +    buf_pos = (int)strlen(buf);
   3.115 +    if (second >= 0) {
   3.116 +      strncpy(&buf[buf_pos], tail, second - first - 2);
   3.117 +      strcpy(&buf[buf_pos + second - first - 2], p2nd);
   3.118 +      tail = nametail + second + 2;
   3.119 +    }
   3.120 +  }
   3.121 +  strcat(buf, tail);      // append rest of name, or all of name
   3.122 +  return buf;
   3.123 +}
   3.124 +
   3.125 +// log_name comes from -XX:LogFile=log_name or -Xloggc:log_name
   3.126 +// in log_name, %p => pipd1234 and
   3.127 +//              %t => YYYY-MM-DD_HH-MM-SS
   3.128 +static const char* make_log_name(const char* log_name, const char* force_directory) {
   3.129 +  char timestr[32];
   3.130 +  get_datetime_string(timestr, sizeof(timestr));
   3.131 +  return make_log_name_internal(log_name, force_directory, os::current_process_id(),
   3.132 +                                timestr);
   3.133 +}
   3.134 +
   3.135 +#ifndef PRODUCT
   3.136 +void test_loggc_filename() {
   3.137 +  int pid;
   3.138 +  char  tms[32];
   3.139 +  char  i_result[FILENAMEBUFLEN];
   3.140 +  const char* o_result;
   3.141 +  get_datetime_string(tms, sizeof(tms));
   3.142 +  pid = os::current_process_id();
   3.143 +
   3.144 +  // test.log
   3.145 +  jio_snprintf(i_result, sizeof(char)*FILENAMEBUFLEN, "test.log", tms);
   3.146 +  o_result = make_log_name_internal("test.log", NULL, pid, tms);
   3.147 +  assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"test.log\", NULL)");
   3.148 +  FREE_C_HEAP_ARRAY(char, o_result, mtInternal);
   3.149 +
   3.150 +  // test-%t-%p.log
   3.151 +  jio_snprintf(i_result, sizeof(char)*FILENAMEBUFLEN, "test-%s-pid%u.log", tms, pid);
   3.152 +  o_result = make_log_name_internal("test-%t-%p.log", NULL, pid, tms);
   3.153 +  assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"test-%%t-%%p.log\", NULL)");
   3.154 +  FREE_C_HEAP_ARRAY(char, o_result, mtInternal);
   3.155 +
   3.156 +  // test-%t%p.log
   3.157 +  jio_snprintf(i_result, sizeof(char)*FILENAMEBUFLEN, "test-%spid%u.log", tms, pid);
   3.158 +  o_result = make_log_name_internal("test-%t%p.log", NULL, pid, tms);
   3.159 +  assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"test-%%t%%p.log\", NULL)");
   3.160 +  FREE_C_HEAP_ARRAY(char, o_result, mtInternal);
   3.161 +
   3.162 +  // %p%t.log
   3.163 +  jio_snprintf(i_result, sizeof(char)*FILENAMEBUFLEN, "pid%u%s.log", pid, tms);
   3.164 +  o_result = make_log_name_internal("%p%t.log", NULL, pid, tms);
   3.165 +  assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"%%p%%t.log\", NULL)");
   3.166 +  FREE_C_HEAP_ARRAY(char, o_result, mtInternal);
   3.167 +
   3.168 +  // %p-test.log
   3.169 +  jio_snprintf(i_result, sizeof(char)*FILENAMEBUFLEN, "pid%u-test.log", pid);
   3.170 +  o_result = make_log_name_internal("%p-test.log", NULL, pid, tms);
   3.171 +  assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"%%p-test.log\", NULL)");
   3.172 +  FREE_C_HEAP_ARRAY(char, o_result, mtInternal);
   3.173 +
   3.174 +  // %t.log
   3.175 +  jio_snprintf(i_result, sizeof(char)*FILENAMEBUFLEN, "%s.log", tms);
   3.176 +  o_result = make_log_name_internal("%t.log", NULL, pid, tms);
   3.177 +  assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"%%t.log\", NULL)");
   3.178 +  FREE_C_HEAP_ARRAY(char, o_result, mtInternal);
   3.179 +}
   3.180 +#endif // PRODUCT
   3.181 +
   3.182  fileStream::fileStream(const char* file_name) {
   3.183    _file = fopen(file_name, "w");
   3.184 -  _need_close = true;
   3.185 +  if (_file != NULL) {
   3.186 +    _need_close = true;
   3.187 +  } else {
   3.188 +    warning("Cannot open file %s due to %s\n", file_name, strerror(errno));
   3.189 +    _need_close = false;
   3.190 +  }
   3.191  }
   3.192  
   3.193  fileStream::fileStream(const char* file_name, const char* opentype) {
   3.194    _file = fopen(file_name, opentype);
   3.195 -  _need_close = true;
   3.196 +  if (_file != NULL) {
   3.197 +    _need_close = true;
   3.198 +  } else {
   3.199 +    warning("Cannot open file %s due to %s\n", file_name, strerror(errno));
   3.200 +    _need_close = false;
   3.201 +  }
   3.202  }
   3.203  
   3.204  void fileStream::write(const char* s, size_t len) {
   3.205 @@ -423,34 +599,51 @@
   3.206    update_position(s, len);
   3.207  }
   3.208  
   3.209 -rotatingFileStream::~rotatingFileStream() {
   3.210 +// dump vm version, os version, platform info, build id,
   3.211 +// memory usage and command line flags into header
   3.212 +void gcLogFileStream::dump_loggc_header() {
   3.213 +  if (is_open()) {
   3.214 +    print_cr(Abstract_VM_Version::internal_vm_info_string());
   3.215 +    os::print_memory_info(this);
   3.216 +    print("CommandLine flags: ");
   3.217 +    CommandLineFlags::printSetFlags(this);
   3.218 +  }
   3.219 +}
   3.220 +
   3.221 +gcLogFileStream::~gcLogFileStream() {
   3.222    if (_file != NULL) {
   3.223      if (_need_close) fclose(_file);
   3.224 -    _file      = NULL;
   3.225 +    _file = NULL;
   3.226 +  }
   3.227 +  if (_file_name != NULL) {
   3.228      FREE_C_HEAP_ARRAY(char, _file_name, mtInternal);
   3.229      _file_name = NULL;
   3.230    }
   3.231  }
   3.232  
   3.233 -rotatingFileStream::rotatingFileStream(const char* file_name) {
   3.234 +gcLogFileStream::gcLogFileStream(const char* file_name) {
   3.235    _cur_file_num = 0;
   3.236    _bytes_written = 0L;
   3.237 -  _file_name = NEW_C_HEAP_ARRAY(char, strlen(file_name)+10, mtInternal);
   3.238 -  jio_snprintf(_file_name, strlen(file_name)+10, "%s.%d", file_name, _cur_file_num);
   3.239 -  _file = fopen(_file_name, "w");
   3.240 -  _need_close = true;
   3.241 +  _file_name = make_log_name(file_name, NULL);
   3.242 +
   3.243 +  // gc log file rotation
   3.244 +  if (UseGCLogFileRotation && NumberOfGCLogFiles > 1) {
   3.245 +    char tempbuf[FILENAMEBUFLEN];
   3.246 +    jio_snprintf(tempbuf, sizeof(tempbuf), "%s.%d" CURRENTAPPX, _file_name, _cur_file_num);
   3.247 +    _file = fopen(tempbuf, "w");
   3.248 +  } else {
   3.249 +    _file = fopen(_file_name, "w");
   3.250 +  }
   3.251 +  if (_file != NULL) {
   3.252 +    _need_close = true;
   3.253 +    dump_loggc_header();
   3.254 +  } else {
   3.255 +    warning("Cannot open file %s due to %s\n", _file_name, strerror(errno));
   3.256 +    _need_close = false;
   3.257 +  }
   3.258  }
   3.259  
   3.260 -rotatingFileStream::rotatingFileStream(const char* file_name, const char* opentype) {
   3.261 -  _cur_file_num = 0;
   3.262 -  _bytes_written = 0L;
   3.263 -  _file_name = NEW_C_HEAP_ARRAY(char, strlen(file_name)+10, mtInternal);
   3.264 -  jio_snprintf(_file_name, strlen(file_name)+10, "%s.%d", file_name, _cur_file_num);
   3.265 -  _file = fopen(_file_name, opentype);
   3.266 -  _need_close = true;
   3.267 -}
   3.268 -
   3.269 -void rotatingFileStream::write(const char* s, size_t len) {
   3.270 +void gcLogFileStream::write(const char* s, size_t len) {
   3.271    if (_file != NULL) {
   3.272      size_t count = fwrite(s, 1, len, _file);
   3.273      _bytes_written += count;
   3.274 @@ -466,7 +659,12 @@
   3.275  // write to gc log file at safepoint. If in future, changes made for mutator threads or
   3.276  // concurrent GC threads to run parallel with VMThread at safepoint, write and rotate_log
   3.277  // must be synchronized.
   3.278 -void rotatingFileStream::rotate_log() {
   3.279 +void gcLogFileStream::rotate_log() {
   3.280 +  char time_msg[FILENAMEBUFLEN];
   3.281 +  char time_str[EXTRACHARLEN];
   3.282 +  char current_file_name[FILENAMEBUFLEN];
   3.283 +  char renamed_file_name[FILENAMEBUFLEN];
   3.284 +
   3.285    if (_bytes_written < (jlong)GCLogFileSize) {
   3.286      return;
   3.287    }
   3.288 @@ -481,27 +679,89 @@
   3.289      // rotate in same file
   3.290      rewind();
   3.291      _bytes_written = 0L;
   3.292 +    jio_snprintf(time_msg, sizeof(time_msg), "File  %s rotated at %s\n",
   3.293 +                 _file_name, os::local_time_string((char *)time_str, sizeof(time_str)));
   3.294 +    write(time_msg, strlen(time_msg));
   3.295 +    dump_loggc_header();
   3.296      return;
   3.297    }
   3.298  
   3.299 -  // rotate file in names file.0, file.1, file.2, ..., file.<MaxGCLogFileNumbers-1>
   3.300 -  // close current file, rotate to next file
   3.301 +#if defined(_WINDOWS)
   3.302 +#ifndef F_OK
   3.303 +#define F_OK 0
   3.304 +#endif
   3.305 +#endif // _WINDOWS
   3.306 +
   3.307 +  // rotate file in names extended_filename.0, extended_filename.1, ...,
   3.308 +  // extended_filename.<NumberOfGCLogFiles - 1>. Current rotation file name will
   3.309 +  // have a form of extended_filename.<i>.current where i is the current rotation
   3.310 +  // file number. After it reaches max file size, the file will be saved and renamed
   3.311 +  // with .current removed from its tail.
   3.312 +  size_t filename_len = strlen(_file_name);
   3.313    if (_file != NULL) {
   3.314 -    _cur_file_num ++;
   3.315 -    if (_cur_file_num >= NumberOfGCLogFiles) _cur_file_num = 0;
   3.316 -    jio_snprintf(_file_name, strlen(Arguments::gc_log_filename()) + 10, "%s.%d",
   3.317 -             Arguments::gc_log_filename(), _cur_file_num);
   3.318 +    jio_snprintf(renamed_file_name, filename_len + EXTRACHARLEN, "%s.%d",
   3.319 +                 _file_name, _cur_file_num);
   3.320 +    jio_snprintf(current_file_name, filename_len + EXTRACHARLEN, "%s.%d" CURRENTAPPX,
   3.321 +                 _file_name, _cur_file_num);
   3.322 +    jio_snprintf(time_msg, sizeof(time_msg), "%s GC log file has reached the"
   3.323 +                           " maximum size. Saved as %s\n",
   3.324 +                           os::local_time_string((char *)time_str, sizeof(time_str)),
   3.325 +                           renamed_file_name);
   3.326 +    write(time_msg, strlen(time_msg));
   3.327 +
   3.328      fclose(_file);
   3.329      _file = NULL;
   3.330 +
   3.331 +    bool can_rename = true;
   3.332 +    if (access(current_file_name, F_OK) != 0) {
   3.333 +      // current file does not exist?
   3.334 +      warning("No source file exists, cannot rename\n");
   3.335 +      can_rename = false;
   3.336 +    }
   3.337 +    if (can_rename) {
   3.338 +      if (access(renamed_file_name, F_OK) == 0) {
   3.339 +        if (remove(renamed_file_name) != 0) {
   3.340 +          warning("Could not delete existing file %s\n", renamed_file_name);
   3.341 +          can_rename = false;
   3.342 +        }
   3.343 +      } else {
   3.344 +        // file does not exist, ok to rename
   3.345 +      }
   3.346 +    }
   3.347 +    if (can_rename && rename(current_file_name, renamed_file_name) != 0) {
   3.348 +      warning("Could not rename %s to %s\n", _file_name, renamed_file_name);
   3.349 +    }
   3.350    }
   3.351 -  _file = fopen(_file_name, "w");
   3.352 +
   3.353 +  _cur_file_num++;
   3.354 +  if (_cur_file_num > NumberOfGCLogFiles - 1) _cur_file_num = 0;
   3.355 +  jio_snprintf(current_file_name,  filename_len + EXTRACHARLEN, "%s.%d" CURRENTAPPX,
   3.356 +               _file_name, _cur_file_num);
   3.357 +  _file = fopen(current_file_name, "w");
   3.358 +
   3.359    if (_file != NULL) {
   3.360      _bytes_written = 0L;
   3.361      _need_close = true;
   3.362 +    // reuse current_file_name for time_msg
   3.363 +    jio_snprintf(current_file_name, filename_len + EXTRACHARLEN,
   3.364 +                 "%s.%d", _file_name, _cur_file_num);
   3.365 +    jio_snprintf(time_msg, sizeof(time_msg), "%s GC log file created %s\n",
   3.366 +                           os::local_time_string((char *)time_str, sizeof(time_str)),
   3.367 +                           current_file_name);
   3.368 +    write(time_msg, strlen(time_msg));
   3.369 +    dump_loggc_header();
   3.370 +    // remove the existing file
   3.371 +    if (access(current_file_name, F_OK) == 0) {
   3.372 +      if (remove(current_file_name) != 0) {
   3.373 +        warning("Could not delete existing file %s\n", current_file_name);
   3.374 +      }
   3.375 +    }
   3.376    } else {
   3.377 -    tty->print_cr("failed to open rotation log file %s due to %s\n",
   3.378 +    warning("failed to open rotation log file %s due to %s\n"
   3.379 +            "Turned off GC log file rotation\n",
   3.380                    _file_name, strerror(errno));
   3.381      _need_close = false;
   3.382 +    FLAG_SET_DEFAULT(UseGCLogFileRotation, false);
   3.383    }
   3.384  }
   3.385  
   3.386 @@ -530,66 +790,6 @@
   3.387    return _log_file != NULL;
   3.388  }
   3.389  
   3.390 -static const char* make_log_name(const char* log_name, const char* force_directory) {
   3.391 -  const char* basename = log_name;
   3.392 -  char file_sep = os::file_separator()[0];
   3.393 -  const char* cp;
   3.394 -  for (cp = log_name; *cp != '\0'; cp++) {
   3.395 -    if (*cp == '/' || *cp == file_sep) {
   3.396 -      basename = cp+1;
   3.397 -    }
   3.398 -  }
   3.399 -  const char* nametail = log_name;
   3.400 -
   3.401 -  // Compute buffer length
   3.402 -  size_t buffer_length;
   3.403 -  if (force_directory != NULL) {
   3.404 -    buffer_length = strlen(force_directory) + strlen(os::file_separator()) +
   3.405 -                    strlen(basename) + 1;
   3.406 -  } else {
   3.407 -    buffer_length = strlen(log_name) + 1;
   3.408 -  }
   3.409 -
   3.410 -  const char* star = strchr(basename, '*');
   3.411 -  int star_pos = (star == NULL) ? -1 : (star - nametail);
   3.412 -  int skip = 1;
   3.413 -  if (star == NULL) {
   3.414 -    // Try %p
   3.415 -    star = strstr(basename, "%p");
   3.416 -    if (star != NULL) {
   3.417 -      skip = 2;
   3.418 -    }
   3.419 -  }
   3.420 -  star_pos = (star == NULL) ? -1 : (star - nametail);
   3.421 -
   3.422 -  char pid[32];
   3.423 -  if (star_pos >= 0) {
   3.424 -    jio_snprintf(pid, sizeof(pid), "%u", os::current_process_id());
   3.425 -    buffer_length += strlen(pid);
   3.426 -  }
   3.427 -
   3.428 -  // Create big enough buffer.
   3.429 -  char *buf = NEW_C_HEAP_ARRAY(char, buffer_length, mtInternal);
   3.430 -
   3.431 -  strcpy(buf, "");
   3.432 -  if (force_directory != NULL) {
   3.433 -    strcat(buf, force_directory);
   3.434 -    strcat(buf, os::file_separator());
   3.435 -    nametail = basename;       // completely skip directory prefix
   3.436 -  }
   3.437 -
   3.438 -  if (star_pos >= 0) {
   3.439 -    // convert foo*bar.log or foo%pbar.log to foo123bar.log
   3.440 -    int buf_pos = (int) strlen(buf);
   3.441 -    strncpy(&buf[buf_pos], nametail, star_pos);
   3.442 -    strcpy(&buf[buf_pos + star_pos], pid);
   3.443 -    nametail += star_pos + skip;  // skip prefix and pid format
   3.444 -  }
   3.445 -
   3.446 -  strcat(buf, nametail);      // append rest of name, or all of name
   3.447 -  return buf;
   3.448 -}
   3.449 -
   3.450  void defaultStream::init_log() {
   3.451    // %%% Need a MutexLocker?
   3.452    const char* log_name = LogFile != NULL ? LogFile : "hotspot.log";
   3.453 @@ -877,11 +1077,8 @@
   3.454  
   3.455    gclog_or_tty = tty; // default to tty
   3.456    if (Arguments::gc_log_filename() != NULL) {
   3.457 -    fileStream * gclog  = UseGCLogFileRotation ?
   3.458 -                          new(ResourceObj::C_HEAP, mtInternal)
   3.459 -                             rotatingFileStream(Arguments::gc_log_filename()) :
   3.460 -                          new(ResourceObj::C_HEAP, mtInternal)
   3.461 -                             fileStream(Arguments::gc_log_filename());
   3.462 +    fileStream * gclog  = new(ResourceObj::C_HEAP, mtInternal)
   3.463 +                             gcLogFileStream(Arguments::gc_log_filename());
   3.464      if (gclog->is_open()) {
   3.465        // now we update the time stamp of the GC log to be synced up
   3.466        // with tty.
     4.1 --- a/src/share/vm/utilities/ostream.hpp	Mon Sep 16 12:43:34 2013 -0700
     4.2 +++ b/src/share/vm/utilities/ostream.hpp	Mon Sep 16 15:35:04 2013 -0700
     4.3 @@ -231,20 +231,24 @@
     4.4    void flush() {};
     4.5  };
     4.6  
     4.7 -class rotatingFileStream : public fileStream {
     4.8 +class gcLogFileStream : public fileStream {
     4.9   protected:
    4.10 -  char*  _file_name;
    4.11 +  const char*  _file_name;
    4.12    jlong  _bytes_written;
    4.13 -  uintx  _cur_file_num;             // current logfile rotation number, from 0 to MaxGCLogFileNumbers-1
    4.14 +  uintx  _cur_file_num;             // current logfile rotation number, from 0 to NumberOfGCLogFiles-1
    4.15   public:
    4.16 -  rotatingFileStream(const char* file_name);
    4.17 -  rotatingFileStream(const char* file_name, const char* opentype);
    4.18 -  rotatingFileStream(FILE* file) : fileStream(file) {}
    4.19 -  ~rotatingFileStream();
    4.20 +  gcLogFileStream(const char* file_name);
    4.21 +  ~gcLogFileStream();
    4.22    virtual void write(const char* c, size_t len);
    4.23    virtual void rotate_log();
    4.24 +  void dump_loggc_header();
    4.25  };
    4.26  
    4.27 +#ifndef PRODUCT
    4.28 +// unit test for checking -Xloggc:<filename> parsing result
    4.29 +void test_loggc_filename();
    4.30 +#endif
    4.31 +
    4.32  void ostream_init();
    4.33  void ostream_init_log();
    4.34  void ostream_exit();

mercurial