< 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 >