< prev index next >

src/share/vm/logging/logFileOutput.cpp

Print this page
rev 10386 : imported patch 8146879.03

@@ -39,12 +39,13 @@
 char        LogFileOutput::_pid_str[PidBufferSize];
 char        LogFileOutput::_vm_start_time_str[StartTimeBufferSize];
 
 LogFileOutput::LogFileOutput(const char* name)
     : LogFileStreamOutput(NULL), _name(os::strdup_check_oom(name, mtLogging)),
-      _file_name(NULL), _archive_name(NULL), _archive_name_len(0), _current_size(0),
-      _rotate_size(0), _current_file(1), _file_count(0), _rotation_semaphore(1) {
+      _file_name(NULL), _archive_name(NULL), _archive_name_len(0),
+      _rotate_size(DefaultRotationFileSize), _file_count(DefaultRotationFileCount),
+      _current_size(0), _current_file(0), _rotation_semaphore(1) {
   _file_name = make_file_name(name, _pid_str, _vm_start_time_str);
 }
 
 void LogFileOutput::set_file_name_parameters(jlong vm_start_time) {
   int res = jio_snprintf(_pid_str, sizeof(_pid_str), "%d", os::current_process_id());

@@ -57,33 +58,80 @@
   assert(res > 0, "VM start time buffer too small.");
 }
 
 LogFileOutput::~LogFileOutput() {
   if (_stream != NULL) {
-    if (_archive_name != NULL) {
-      archive();
-    }
     if (fclose(_stream) != 0) {
       jio_fprintf(defaultStream::error_stream(), "Could not close log file '%s' (%s).\n",
                   _file_name, strerror(errno));
     }
   }
   os::free(_archive_name);
   os::free(_file_name);
   os::free(const_cast<char*>(_name));
 }
 
-size_t LogFileOutput::parse_value(const char* value_str) {
+static size_t parse_value(const char* value_str) {
   char* end;
   unsigned long long value = strtoull(value_str, &end, 10);
   if (!isdigit(*value_str) || end != value_str + strlen(value_str) || value >= SIZE_MAX) {
     return SIZE_MAX;
   }
   return value;
 }
 
-bool LogFileOutput::configure_rotation(const char* options) {
+static bool file_exists(const char* filename) {
+  struct stat dummy_stat;
+  return os::stat(filename, &dummy_stat) == 0;
+}
+
+static uint number_of_digits(uint number) {
+  double d = static_cast<double>(number);
+  uint res = 1 + log10(d);
+  return res;
+}
+
+static uint next_file_number(const char* filename,
+                             uint number_of_digits,
+                             uint filecount) {
+  bool found = false;
+  uint next_num = 0;
+
+  // len is filename + dot + digits + null char
+  size_t len = strlen(filename) + number_of_digits + 2;
+  char* archive_name = NEW_C_HEAP_ARRAY(char, len, mtLogging);
+  char* oldest_name = NEW_C_HEAP_ARRAY(char, len, mtLogging);
+
+  for (uint i = 0; i < filecount; i++) {
+    int ret = jio_snprintf(archive_name, len, "%s.%0*u",
+                           filename, number_of_digits, i);
+    assert(ret > 0 && static_cast<size_t>(ret) == len - 1,
+           "incorrect buffer length calculation");
+
+    // Stop looking if we find an unused file name
+    if (!file_exists(archive_name)) {
+      next_num = i;
+      found = true;
+      break;
+    }
+
+    // Keep track of oldest existing log file
+    if (!found
+        || os::compare_file_modified_times(oldest_name, archive_name) > 0) {
+      strcpy(oldest_name, archive_name);
+      next_num = i;
+      found = true;
+    }
+  }
+
+  FREE_C_HEAP_ARRAY(char, oldest_name);
+  FREE_C_HEAP_ARRAY(char, archive_name);
+  assert(found, "should always find a next number");
+  return next_num;
+}
+
+bool LogFileOutput::configure(const char* options) {
   if (options == NULL || strlen(options) == 0) {
     return true;
   }
   bool success = true;
   char* opts = os::strdup_check_oom(options, mtLogging);

@@ -110,13 +158,10 @@
       if (value == SIZE_MAX || value >= UINT_MAX) {
         success = false;
         break;
       }
       _file_count = static_cast<uint>(value);
-      _file_count_max_digits = static_cast<uint>(log10(static_cast<double>(_file_count)) + 1);
-      _archive_name_len = 2 + strlen(_file_name) + _file_count_max_digits;
-      _archive_name = NEW_C_HEAP_ARRAY(char, _archive_name_len, mtLogging);
     } else if (strcmp(FileSizeOptionKey, key) == 0) {
       size_t value = parse_value(value_str);
       if (value == SIZE_MAX || value > SIZE_MAX / K) {
         success = false;
         break;

@@ -132,18 +177,44 @@
   os::free(opts);
   return success;
 }
 
 bool LogFileOutput::initialize(const char* options) {
-  if (!configure_rotation(options)) {
+  if (!configure(options)) {
     return false;
   }
+
+  if (_file_count > 0) {
+    _file_count_max_digits = number_of_digits(_file_count - 1); // -1 for 0-index
+    _archive_name_len = 2 + strlen(_file_name) + _file_count_max_digits;
+    _archive_name = NEW_C_HEAP_ARRAY(char, _archive_name_len, mtLogging);
+  }
+
+  log_trace(logging)("Initializing logging to file '%s' (filecount: %u"
+                     ", filesize: " SIZE_FORMAT " KiB).",
+                     _file_name, _file_count, _rotate_size / K);
+
+  if (_file_count > 0 && file_exists(_file_name)) {
+    _current_file = next_file_number(_file_name,
+                                     _file_count_max_digits,
+                                     _file_count);
+    log_trace(logging)("Existing log file found, saving it as '%s.%0*u'.",
+                       _file_name, _file_count_max_digits, _current_file);
+    archive();
+  }
+
   _stream = fopen(_file_name, FileOpenMode);
   if (_stream == NULL) {
-    log_error(logging)("Could not open log file '%s' (%s).\n", _file_name, strerror(errno));
+    log_error(logging)("Could not open log file '%s' (%s).", _file_name, strerror(errno));
     return false;
   }
+
+  if (_file_count == 0) {
+    log_trace(logging)("Truncating log file");
+    os::ftruncate(os::fileno(_stream), 0);
+  }
+
   return true;
 }
 
 int LogFileOutput::write(const LogDecorations& decorations, const char* msg) {
   if (_stream == NULL) {

@@ -208,11 +279,14 @@
     return;
   }
 
   // Reset accumulated size, increase current file counter, and check for file count wrap-around.
   _current_size = 0;
-  _current_file = (_current_file >= _file_count ? 1 : _current_file + 1);
+  _current_file++;
+  if (_current_file == _file_count) {
+    _current_file = 0;
+  }
 }
 
 char* LogFileOutput::make_file_name(const char* file_name,
                                     const char* pid_string,
                                     const char* timestamp_string) {
< prev index next >