src/share/vm/utilities/ostream.cpp
Index Unified diffs Context diffs Sdiffs Wdiffs Patch New Old Previous File Next File 7164841 Sdiff src/share/vm/utilities

src/share/vm/utilities/ostream.cpp

Print this page
7164841: Improvements to the GC log file rotation


 325       assert(rm == NULL || Thread::current()->current_resource_mark() == rm,
 326              "stringStream is re-allocated with a different ResourceMark");
 327       buffer = NEW_RESOURCE_ARRAY(char, end);
 328       strncpy(buffer, oldbuf, buffer_pos);
 329       buffer_length = end;
 330     }
 331   }
 332   // invariant: buffer is always null-terminated
 333   guarantee(buffer_pos + write_len + 1 <= buffer_length, "stringStream oob");
 334   buffer[buffer_pos + write_len] = 0;
 335   strncpy(buffer + buffer_pos, s, write_len);
 336   buffer_pos += write_len;
 337 
 338   // Note that the following does not depend on write_len.
 339   // This means that position and count get updated
 340   // even when overflow occurs.
 341   update_position(s, len);
 342 }
 343 
 344 char* stringStream::as_string() {
 345   char* copy = NEW_RESOURCE_ARRAY(char, buffer_pos+1);
 346   strncpy(copy, buffer, buffer_pos);
 347   copy[buffer_pos] = 0;  // terminating null
 348   return copy;
 349 }
 350 
 351 stringStream::~stringStream() {}
 352 
 353 xmlStream*   xtty;
 354 outputStream* tty;
 355 outputStream* gclog_or_tty;
 356 extern Mutex* tty_lock;
 357 





































































































 358 fileStream::fileStream(const char* file_name) {
 359   _file = fopen(file_name, "w");

 360   _need_close = true;


 361 }
 362 
 363 fileStream::fileStream(const char* file_name, const char* opentype) {
 364   _file = fopen(file_name, opentype);

 365   _need_close = true;


 366 }
 367 
 368 void fileStream::write(const char* s, size_t len) {
 369   if (_file != NULL)  {
 370     // Make an unused local variable to avoid warning from gcc 4.x compiler.
 371     size_t count = fwrite(s, 1, len, _file);
 372   }
 373   update_position(s, len);
 374 }
 375 
 376 long fileStream::fileSize() {
 377   long size = -1;
 378   if (_file != NULL) {
 379     long pos  = ::ftell(_file);
 380     if (::fseek(_file, 0, SEEK_END) == 0) {
 381       size = ::ftell(_file);
 382     }
 383     ::fseek(_file, pos, SEEK_SET);
 384   }
 385   return size;


 410 
 411 fdStream::~fdStream() {
 412   if (_fd != -1) {
 413     if (_need_close) close(_fd);
 414     _fd = -1;
 415   }
 416 }
 417 
 418 void fdStream::write(const char* s, size_t len) {
 419   if (_fd != -1) {
 420     // Make an unused local variable to avoid warning from gcc 4.x compiler.
 421     size_t count = ::write(_fd, s, (int)len);
 422   }
 423   update_position(s, len);
 424 }
 425 
 426 rotatingFileStream::~rotatingFileStream() {
 427   if (_file != NULL) {
 428     if (_need_close) fclose(_file);
 429     _file      = NULL;


 430     FREE_C_HEAP_ARRAY(char, _file_name, mtInternal);
 431     _file_name = NULL;
 432   }
 433 }
 434 
 435 rotatingFileStream::rotatingFileStream(const char* file_name) {

 436   _cur_file_num = 0;
 437   _bytes_written = 0L;
 438   _file_name = NEW_C_HEAP_ARRAY(char, strlen(file_name)+10, mtInternal);
 439   jio_snprintf(_file_name, strlen(file_name)+10, "%s.%d", file_name, _cur_file_num);





 440   _file = fopen(_file_name, "w");

 441   _need_close = true;

 442 }
 443 
 444 rotatingFileStream::rotatingFileStream(const char* file_name, const char* opentype) {
 445   _cur_file_num = 0;
 446   _bytes_written = 0L;
 447   _file_name = NEW_C_HEAP_ARRAY(char, strlen(file_name)+10, mtInternal);
 448   jio_snprintf(_file_name, strlen(file_name)+10, "%s.%d", file_name, _cur_file_num);
 449   _file = fopen(_file_name, opentype);
 450   _need_close = true;
 451 }
 452 
 453 void rotatingFileStream::write(const char* s, size_t len) {
 454   if (_file != NULL) {
 455     size_t count = fwrite(s, 1, len, _file);
 456     _bytes_written += count;
 457   }
 458   update_position(s, len);
 459 }
 460 
 461 // rotate_log must be called from VMThread at safepoint. In case need change parameters
 462 // for gc log rotation from thread other than VMThread, a sub type of VM_Operation
 463 // should be created and be submitted to VMThread's operation queue. DO NOT call this
 464 // function directly. Currently, it is safe to rotate log at safepoint through VMThread.
 465 // That is, no mutator threads and concurrent GC threads run parallel with VMThread to
 466 // write to gc log file at safepoint. If in future, changes made for mutator threads or
 467 // concurrent GC threads to run parallel with VMThread at safepoint, write and rotate_log
 468 // must be synchronized.
 469 void rotatingFileStream::rotate_log() {





 470   if (_bytes_written < (jlong)GCLogFileSize) {
 471     return;
 472   }
 473 
 474 #ifdef ASSERT
 475   Thread *thread = Thread::current();
 476   assert(thread == NULL ||
 477          (thread->is_VM_thread() && SafepointSynchronize::is_at_safepoint()),
 478          "Must be VMThread at safepoint");
 479 #endif
 480   if (NumberOfGCLogFiles == 1) {
 481     // rotate in same file
 482     rewind();
 483     _bytes_written = 0L;




 484     return;
 485   }
 486 
 487   // rotate file in names file.0, file.1, file.2, ..., file.<MaxGCLogFileNumbers-1>
 488   // close current file, rotate to next file










 489   if (_file != NULL) {
 490     _cur_file_num ++;
 491     if (_cur_file_num >= NumberOfGCLogFiles) _cur_file_num = 0;
 492     jio_snprintf(_file_name, strlen(Arguments::gc_log_filename()) + 10, "%s.%d",
 493              Arguments::gc_log_filename(), _cur_file_num);






 494     fclose(_file);
 495     _file = NULL;






 496   }
 497   _file = fopen(_file_name, "w");




















 498   if (_file != NULL) {
 499     _bytes_written = 0L;
 500     _need_close = true;














 501   } else {
 502     tty->print_cr("failed to open rotation log file %s due to %s\n",

 503                   _file_name, strerror(errno));
 504     _need_close = false;

 505   }
 506 }
 507 
 508 defaultStream* defaultStream::instance = NULL;
 509 int defaultStream::_output_fd = 1;
 510 int defaultStream::_error_fd  = 2;
 511 FILE* defaultStream::_output_stream = stdout;
 512 FILE* defaultStream::_error_stream  = stderr;
 513 
 514 #define LOG_MAJOR_VERSION 160
 515 #define LOG_MINOR_VERSION 1
 516 
 517 void defaultStream::init() {
 518   _inited = true;
 519   if (LogVMOutput || LogCompilation) {
 520     init_log();
 521   }
 522 }
 523 
 524 bool defaultStream::has_log_file() {




 325       assert(rm == NULL || Thread::current()->current_resource_mark() == rm,
 326              "stringStream is re-allocated with a different ResourceMark");
 327       buffer = NEW_RESOURCE_ARRAY(char, end);
 328       strncpy(buffer, oldbuf, buffer_pos);
 329       buffer_length = end;
 330     }
 331   }
 332   // invariant: buffer is always null-terminated
 333   guarantee(buffer_pos + write_len + 1 <= buffer_length, "stringStream oob");
 334   buffer[buffer_pos + write_len] = 0;
 335   strncpy(buffer + buffer_pos, s, write_len);
 336   buffer_pos += write_len;
 337 
 338   // Note that the following does not depend on write_len.
 339   // This means that position and count get updated
 340   // even when overflow occurs.
 341   update_position(s, len);
 342 }
 343 
 344 char* stringStream::as_string() {
 345   char* copy = NEW_RESOURCE_ARRAY(char, buffer_pos + 1);
 346   strncpy(copy, buffer, buffer_pos);
 347   copy[buffer_pos] = 0;  // terminating null
 348   return copy;
 349 }
 350 
 351 stringStream::~stringStream() {}
 352 
 353 xmlStream*   xtty;
 354 outputStream* tty;
 355 outputStream* gclog_or_tty;
 356 extern Mutex* tty_lock;
 357 
 358 #define EXTRACHARLEN   32
 359 #define CURRENTAPPX    ".current"
 360 #define FILENAMEBUFLEN  1024
 361 // convert YYYY-MM-DD HH:MM:SS to YYYY-MM-DD_HH-MM-SS
 362 char* get_datetime_string(char *buf, size_t len) {
 363   os::local_time_string(buf, len);
 364   int i = strlen(buf);
 365   while (i-- >= 0) {
 366     if (buf[i] == ' ') buf[i] = '_';
 367     else if (buf[i] == ':') buf[i] = '-';
 368   }
 369   return buf;
 370 }
 371 
 372 char* extend_file_name(const char* file_name) {
 373   char*  extended_name = NULL;
 374   char   timestr[EXTRACHARLEN];
 375   char   pidtext[EXTRACHARLEN];
 376   const char*  spp = strstr(file_name, "%p");
 377   const char*  spt = strstr(file_name, "%t");
 378   int pp = (spp != NULL) ? spp - file_name : -1;
 379   int pt = (spt != NULL) ? spt - file_name : -1;
 380 
 381   if (pp < 0 && pt < 0) {
 382     extended_name = NEW_C_HEAP_ARRAY(char, strlen(file_name) + 1, mtInternal);
 383     strcpy(extended_name, file_name);
 384     return extended_name;
 385   }
 386 
 387   if (pp > 0) {
 388     jio_snprintf(pidtext, sizeof(pidtext), "pid%d", os::current_process_id());
 389   } else {
 390     pidtext[0] = '\0';
 391   }
 392 
 393   if (pt > 0) {
 394     get_datetime_string(timestr, sizeof(timestr));
 395   } else {
 396     timestr[0] = '\0';
 397   }
 398 
 399   size_t len = strlen(file_name) + strlen(pidtext) + strlen(timestr) + 2 * EXTRACHARLEN;
 400   extended_name = NEW_C_HEAP_ARRAY(char, len, mtInternal);
 401   if (pp > 0 && pt > 0 ) {
 402     // *%p*%t*
 403     if (pp < pt) {
 404       memcpy(extended_name, file_name, (size_t)pp);
 405       extended_name[pp] = '\0';
 406       strcat(extended_name, pidtext);
 407       size_t t_len  = strlen(extended_name);
 408       if (pt - pp > 2) {
 409         memcpy(extended_name + t_len, file_name + pp + 2, pt - pp - 2);
 410         extended_name[t_len + pt - pp - 2] = '\0';
 411       }
 412       strcat(extended_name, timestr);
 413       strcat(extended_name, file_name + pt + 2);
 414     // *%t*%p*
 415     } else {
 416       memcpy(extended_name, file_name, (size_t)(pt));
 417       extended_name[pt] = '\0';
 418       strcat(extended_name, timestr);
 419       size_t t_len  = strlen(extended_name);
 420       if (pp - pt > 2) {
 421         memcpy(extended_name + t_len, file_name + pt + 2, pp - pt - 2);
 422         extended_name[t_len + pp - pt - 2] = '\0';
 423       }
 424       strcat(extended_name, pidtext);
 425       strcat(extended_name, file_name + pp + 2);
 426     }
 427     return extended_name;
 428   }
 429 
 430   if (pp > 0) {
 431     // only requested pid
 432     memcpy(extended_name, file_name, (size_t)pp);
 433     extended_name[pp] = '\0';
 434     strcat(extended_name, pidtext); 
 435     strcat(extended_name, file_name + pp + 2);
 436   }
 437   
 438   if (pt > 0) {
 439     // only requested timestamp
 440     memcpy(extended_name, file_name, (size_t)pt);
 441     extended_name[pt] = '\0';
 442     strcat(extended_name, timestr); 
 443     strcat(extended_name, file_name + pt + 2);
 444   }
 445   return extended_name;
 446 }
 447 
 448 // log vm version, os verison, platform info, build id,
 449 // memory usage and command line flags into head of fileStream
 450 void fileStream::dump_loggc_header() {
 451   if(is_open()) {
 452     this->print_cr(Abstract_VM_Version::internal_vm_info_string());
 453     os::print_memory_info(this);
 454     this->print("CommandLine flags: ");
 455     CommandLineFlags::printSetFlags(this);
 456   }
 457 }
 458 
 459 fileStream::fileStream(const char* file_name) {
 460   char* f_name = extend_file_name(file_name);
 461   _file = fopen(f_name, "w");
 462   _need_close = true;
 463   FREE_C_HEAP_ARRAY(char, f_name, mtInternal);
 464   dump_loggc_header();
 465 }
 466 
 467 fileStream::fileStream(const char* file_name, const char* opentype) {
 468   char* f_name = extend_file_name(file_name);
 469   _file = fopen(f_name, opentype);
 470   _need_close = true;
 471   FREE_C_HEAP_ARRAY(char, f_name, mtInternal);
 472   dump_loggc_header();
 473 }
 474 
 475 void fileStream::write(const char* s, size_t len) {
 476   if (_file != NULL)  {
 477     // Make an unused local variable to avoid warning from gcc 4.x compiler.
 478     size_t count = fwrite(s, 1, len, _file);
 479   }
 480   update_position(s, len);
 481 }
 482 
 483 long fileStream::fileSize() {
 484   long size = -1;
 485   if (_file != NULL) {
 486     long pos  = ::ftell(_file);
 487     if (::fseek(_file, 0, SEEK_END) == 0) {
 488       size = ::ftell(_file);
 489     }
 490     ::fseek(_file, pos, SEEK_SET);
 491   }
 492   return size;


 517 
 518 fdStream::~fdStream() {
 519   if (_fd != -1) {
 520     if (_need_close) close(_fd);
 521     _fd = -1;
 522   }
 523 }
 524 
 525 void fdStream::write(const char* s, size_t len) {
 526   if (_fd != -1) {
 527     // Make an unused local variable to avoid warning from gcc 4.x compiler.
 528     size_t count = ::write(_fd, s, (int)len);
 529   }
 530   update_position(s, len);
 531 }
 532 
 533 rotatingFileStream::~rotatingFileStream() {
 534   if (_file != NULL) {
 535     if (_need_close) fclose(_file);
 536     _file = NULL;
 537   }
 538   if (_file_name != NULL) {
 539     FREE_C_HEAP_ARRAY(char, _file_name, mtInternal);
 540     _file_name = NULL;
 541   }
 542 }
 543 
 544 rotatingFileStream::rotatingFileStream(const char* file_name) {
 545   assert(UseGCLogFileRotation, "Should use UseGCLogFileRotation");
 546   _cur_file_num = 0;
 547   _bytes_written = 0L;
 548   _file_name = extend_file_name(file_name);
 549 
 550   if (NumberOfGCLogFiles > 1) {
 551     char tempbuf[FILENAMEBUFLEN];
 552     jio_snprintf(tempbuf, sizeof(tempbuf), "%s.%d" CURRENTAPPX, _file_name, _cur_file_num);
 553     _file = fopen(tempbuf, "w");
 554   } else {
 555     _file = fopen(_file_name, "w");
 556   }
 557   _need_close = true;
 558   dump_loggc_header();
 559 }
 560 









 561 void rotatingFileStream::write(const char* s, size_t len) {
 562   if (_file != NULL) {
 563     size_t count = fwrite(s, 1, len, _file);
 564     _bytes_written += count;
 565   }
 566   update_position(s, len);
 567 }
 568 
 569 // rotate_log must be called from VMThread at safepoint. In case need change parameters
 570 // for gc log rotation from thread other than VMThread, a sub type of VM_Operation
 571 // should be created and be submitted to VMThread's operation queue. DO NOT call this
 572 // function directly. Currently, it is safe to rotate log at safepoint through VMThread.
 573 // That is, no mutator threads and concurrent GC threads run parallel with VMThread to
 574 // write to gc log file at safepoint. If in future, changes made for mutator threads or
 575 // concurrent GC threads to run parallel with VMThread at safepoint, write and rotate_log
 576 // must be synchronized.
 577 void rotatingFileStream::rotate_log() {
 578   char time_msg[FILENAMEBUFLEN];
 579   char time_str[EXTRACHARLEN];
 580   char current_file_name[FILENAMEBUFLEN];
 581   char renamed_file_name[FILENAMEBUFLEN];
 582 
 583   if (_bytes_written < (jlong)GCLogFileSize) {
 584     return;
 585   }
 586 
 587 #ifdef ASSERT
 588   Thread *thread = Thread::current();
 589   assert(thread == NULL ||
 590          (thread->is_VM_thread() && SafepointSynchronize::is_at_safepoint()),
 591          "Must be VMThread at safepoint");
 592 #endif
 593   if (NumberOfGCLogFiles == 1) {
 594     // rotate in same file
 595     rewind();
 596     _bytes_written = 0L;
 597     jio_snprintf(time_msg, sizeof(time_msg), "File  %s rotated at %s\n",
 598                  _file_name, os::local_time_string((char *)time_str, sizeof(time_str)));
 599     this->write(time_msg, strlen(time_msg));
 600     dump_loggc_header();
 601     return;
 602   }
 603 
 604 #if defined(_WINDOWS)
 605 #ifndef F_OK
 606 #define F_OK 0
 607 #endif
 608 #endif // _WINDOWS
 609 
 610   // rotate file in names extended_filename.0, extended_filename.1, ...,
 611   // extended_filename.<NumberOfGCLogFiles - 1>. Current rotation file name will
 612   // have a form of extended_filename.<i>.current where i is the current rotation
 613   // file number. After it reaches max file size, the file will be saved and renamed
 614   // with .current removed from its tail.
 615   size_t filename_len = strlen(_file_name);
 616   if (_file != NULL) {
 617     jio_snprintf(renamed_file_name, filename_len + EXTRACHARLEN, "%s.%d",
 618                  _file_name, _cur_file_num);
 619     jio_snprintf(current_file_name, filename_len + EXTRACHARLEN, "%s.%d" CURRENTAPPX, 
 620                  _file_name, _cur_file_num);
 621     jio_snprintf(time_msg, sizeof(time_msg), "%s GC log file has reached the"
 622                            " maximum size. Saved as %s\n",
 623                            os::local_time_string((char *)time_str, sizeof(time_str)),
 624                            renamed_file_name);
 625     this->write(time_msg, strlen(time_msg));
 626 
 627     fclose(_file);
 628     _file = NULL;
 629 
 630     bool can_rename = true;
 631     if (access(current_file_name, F_OK) != 0) {
 632       // current file does not exist?
 633       warning("No source file exists, cannot rename\n");
 634       can_rename = false;
 635     }
 636     if (can_rename) {
 637       if (access(renamed_file_name, F_OK) == 0) {
 638         if (remove(renamed_file_name) != 0) {
 639           warning("Could not delete existing file %s\n", renamed_file_name);
 640           can_rename = false;
 641         }
 642       } else {
 643         // file does not exist, ok to rename
 644       }
 645     }
 646     if (can_rename && rename(current_file_name, renamed_file_name) != 0) {
 647       warning("Could not rename %s to %s\n", _file_name, renamed_file_name);
 648     }
 649   }
 650 
 651   _cur_file_num++;
 652   if (_cur_file_num > NumberOfGCLogFiles - 1) _cur_file_num = 0;
 653   jio_snprintf(current_file_name,  filename_len + EXTRACHARLEN, "%s.%d" CURRENTAPPX,
 654                _file_name, _cur_file_num);
 655   _file = fopen(current_file_name, "w");
 656 
 657   if (_file != NULL) {
 658     _bytes_written = 0L;
 659     _need_close = true;
 660     // reuse current_file_name for time_msg
 661     jio_snprintf(current_file_name, filename_len + EXTRACHARLEN,
 662                  "%s.%d", _file_name, _cur_file_num);
 663     jio_snprintf(time_msg, sizeof(time_msg), "%s GC log file created %s\n",
 664                            os::local_time_string((char *)time_str, sizeof(time_str)),
 665                            current_file_name);
 666     this->write(time_msg, strlen(time_msg));
 667     dump_loggc_header();
 668     // remove the existing file 
 669     if (access(current_file_name, F_OK) == 0) {
 670       if (remove(current_file_name) != 0) {
 671         warning("Could not delete existing file %s\n", current_file_name);
 672       }
 673     }
 674   } else {
 675     warning("failed to open rotation log file %s due to %s\n"
 676             "Turned off GC log file rotation\n",
 677                   _file_name, strerror(errno));
 678     _need_close = false;
 679     FLAG_SET_DEFAULT(UseGCLogFileRotation, false);
 680   }
 681 }
 682 
 683 defaultStream* defaultStream::instance = NULL;
 684 int defaultStream::_output_fd = 1;
 685 int defaultStream::_error_fd  = 2;
 686 FILE* defaultStream::_output_stream = stdout;
 687 FILE* defaultStream::_error_stream  = stderr;
 688 
 689 #define LOG_MAJOR_VERSION 160
 690 #define LOG_MINOR_VERSION 1
 691 
 692 void defaultStream::init() {
 693   _inited = true;
 694   if (LogVMOutput || LogCompilation) {
 695     init_log();
 696   }
 697 }
 698 
 699 bool defaultStream::has_log_file() {


src/share/vm/utilities/ostream.cpp
Index Unified diffs Context diffs Sdiffs Wdiffs Patch New Old Previous File Next File