Mon, 16 Sep 2013 15:35:04 -0700
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
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();