Chromium Code Reviews| Index: base/files/important_file_writer.cc |
| diff --git a/base/files/important_file_writer.cc b/base/files/important_file_writer.cc |
| index 0696c96b6c955e388dcb0f6af8398ccb9033f8cb..48ab6d2e61d1b9ffef9302ca8be96bab87d606e7 100644 |
| --- a/base/files/important_file_writer.cc |
| +++ b/base/files/important_file_writer.cc |
| @@ -19,6 +19,7 @@ |
| #include "base/files/file_util.h" |
| #include "base/logging.h" |
| #include "base/macros.h" |
| +#include "base/metrics/histogram_functions.h" |
| #include "base/metrics/histogram_macros.h" |
| #include "base/numerics/safe_conversions.h" |
| #include "base/strings/string_number_conversions.h" |
| @@ -49,10 +50,38 @@ enum TempFileFailure { |
| TEMP_FILE_FAILURE_MAX |
| }; |
| -void LogFailure(const FilePath& path, TempFileFailure failure_code, |
| +// Helper function to write samples to a histogram with a dynamically assigned |
| +// histogram name. Works with different error code types convertible to int |
| +// which is the actual argument type of UmaHistogramExactLinear. |
| +template <typename SampleType> |
| +typename std::enable_if<std::is_convertible<SampleType, int>::value>::type |
| +UmaHistogramExactLinearWithSuffix(const char* histogram_name, |
| + const char* histogram_suffix, |
| + SampleType add_sample, |
| + SampleType max_sample) { |
| + DCHECK(histogram_name); |
| + auto histogram_full_name_length = strlen(histogram_name); |
| + if (histogram_suffix && *histogram_suffix) |
| + histogram_full_name_length += |
| + strlen(histogram_suffix) + 1; // Also account for a dot. |
|
dcheng
2017/06/07 22:56:39
To be honest, I don't know that it's worth the eff
xaerox
2017/06/08 05:52:53
I agree that one additional reallocation is worth
|
| + std::string histogram_full_name; |
| + histogram_full_name.reserve(histogram_full_name_length); |
| + histogram_full_name.append(histogram_name); |
| + if (histogram_suffix && *histogram_suffix) { |
| + histogram_full_name.append("."); |
| + histogram_full_name.append(histogram_suffix); |
| + } |
| + UmaHistogramExactLinear(histogram_full_name, static_cast<int>(add_sample), |
| + static_cast<int>(max_sample)); |
| +} |
| + |
| +void LogFailure(const FilePath& path, |
| + StringPiece histogram_suffix, |
| + TempFileFailure failure_code, |
| StringPiece message) { |
| - UMA_HISTOGRAM_ENUMERATION("ImportantFile.TempFileFailures", failure_code, |
| - TEMP_FILE_FAILURE_MAX); |
| + UmaHistogramExactLinearWithSuffix("ImportantFile.TempFileFailures", |
| + histogram_suffix.data(), failure_code, |
| + TEMP_FILE_FAILURE_MAX); |
| DPLOG(WARNING) << "temp file failure: " << path.value() << " : " << message; |
| } |
| @@ -62,21 +91,43 @@ void WriteScopedStringToFileAtomically( |
| const FilePath& path, |
| std::unique_ptr<std::string> data, |
| Closure before_write_callback, |
| - Callback<void(bool success)> after_write_callback) { |
| + Callback<void(bool success)> after_write_callback, |
| + const std::string& histogram_suffix) { |
| if (!before_write_callback.is_null()) |
| before_write_callback.Run(); |
| - bool result = ImportantFileWriter::WriteFileAtomically(path, *data); |
| + bool result = ImportantFileWriter::WriteFileAtomically( |
| + path, *data, histogram_suffix.c_str()); |
|
dcheng
2017/06/07 22:56:39
No need to call c_str() for this
xaerox
2017/06/08 05:52:53
Done.
|
| if (!after_write_callback.is_null()) |
| after_write_callback.Run(result); |
| } |
| +base::File::Error GetLastFileError() { |
| +#if defined(OS_WIN) |
| + return base::File::OSErrorToFileError(::GetLastError()); |
| +#elif defined(OS_POSIX) |
| + return base::File::OSErrorToFileError(errno); |
| +#else |
| + return base::File::FILE_OK; |
| +#endif |
| +} |
| + |
| +void DeleteTmpFile(const FilePath& tmp_file_path, |
| + StringPiece histogram_suffix) { |
| + if (!DeleteFile(tmp_file_path, false)) { |
| + UmaHistogramExactLinearWithSuffix( |
| + "ImportantFile.FileDeleteError", histogram_suffix.data(), |
| + -GetLastFileError(), -base::File::FILE_ERROR_MAX); |
| + } |
| +} |
| + |
| } // namespace |
| // static |
| bool ImportantFileWriter::WriteFileAtomically(const FilePath& path, |
| - StringPiece data) { |
| + StringPiece data, |
| + StringPiece histogram_suffix) { |
| #if defined(OS_CHROMEOS) |
| // On Chrome OS, chrome gets killed when it cannot finish shutdown quickly, |
| // and this function seems to be one of the slowest shutdown steps. |
| @@ -97,13 +148,21 @@ bool ImportantFileWriter::WriteFileAtomically(const FilePath& path, |
| // is securely created. |
| FilePath tmp_file_path; |
| if (!CreateTemporaryFileInDir(path.DirName(), &tmp_file_path)) { |
| - LogFailure(path, FAILED_CREATING, "could not create temporary file"); |
| + UmaHistogramExactLinearWithSuffix( |
| + "ImportantFile.FileCreateError", histogram_suffix.data(), |
| + -GetLastFileError(), -base::File::FILE_ERROR_MAX); |
| + LogFailure(path, histogram_suffix, FAILED_CREATING, |
| + "could not create temporary file"); |
| return false; |
| } |
| File tmp_file(tmp_file_path, File::FLAG_OPEN | File::FLAG_WRITE); |
| if (!tmp_file.IsValid()) { |
| - LogFailure(path, FAILED_OPENING, "could not open temporary file"); |
| + UmaHistogramExactLinearWithSuffix( |
| + "ImportantFile.FileOpenError", histogram_suffix.data(), |
| + -tmp_file.error_details(), -base::File::FILE_ERROR_MAX); |
| + LogFailure(path, histogram_suffix, FAILED_OPENING, |
| + "could not open temporary file"); |
| DeleteFile(tmp_file_path, false); |
| return false; |
| } |
| @@ -111,25 +170,35 @@ bool ImportantFileWriter::WriteFileAtomically(const FilePath& path, |
| // If this fails in the wild, something really bad is going on. |
| const int data_length = checked_cast<int32_t>(data.length()); |
| int bytes_written = tmp_file.Write(0, data.data(), data_length); |
| + if (bytes_written < data_length) { |
| + UmaHistogramExactLinearWithSuffix( |
| + "ImportantFile.FileWriteError", histogram_suffix.data(), |
| + -GetLastFileError(), -base::File::FILE_ERROR_MAX); |
| + } |
| bool flush_success = tmp_file.Flush(); |
| tmp_file.Close(); |
| if (bytes_written < data_length) { |
| - LogFailure(path, FAILED_WRITING, "error writing, bytes_written=" + |
| - IntToString(bytes_written)); |
| - DeleteFile(tmp_file_path, false); |
| + LogFailure(path, histogram_suffix, FAILED_WRITING, |
| + "error writing, bytes_written=" + IntToString(bytes_written)); |
| + DeleteTmpFile(tmp_file_path, histogram_suffix.data()); |
| return false; |
| } |
| if (!flush_success) { |
| - LogFailure(path, FAILED_FLUSHING, "error flushing"); |
| - DeleteFile(tmp_file_path, false); |
| + LogFailure(path, histogram_suffix, FAILED_FLUSHING, "error flushing"); |
| + DeleteTmpFile(tmp_file_path, histogram_suffix); |
| return false; |
| } |
| - if (!ReplaceFile(tmp_file_path, path, nullptr)) { |
| - LogFailure(path, FAILED_RENAMING, "could not rename temporary file"); |
| - DeleteFile(tmp_file_path, false); |
| + base::File::Error replace_file_error = base::File::FILE_OK; |
| + if (!ReplaceFile(tmp_file_path, path, &replace_file_error)) { |
| + UmaHistogramExactLinearWithSuffix( |
| + "ImportantFile.FileRenameError", histogram_suffix.data(), |
| + -replace_file_error, -base::File::FILE_ERROR_MAX); |
| + LogFailure(path, histogram_suffix, FAILED_RENAMING, |
| + "could not rename temporary file"); |
| + DeleteTmpFile(tmp_file_path, histogram_suffix); |
| return false; |
| } |
| @@ -138,19 +207,23 @@ bool ImportantFileWriter::WriteFileAtomically(const FilePath& path, |
| ImportantFileWriter::ImportantFileWriter( |
| const FilePath& path, |
| - scoped_refptr<SequencedTaskRunner> task_runner) |
| + scoped_refptr<SequencedTaskRunner> task_runner, |
| + StringPiece histogram_suffix) |
| : ImportantFileWriter(path, |
| std::move(task_runner), |
| - kDefaultCommitInterval) {} |
| + kDefaultCommitInterval, |
| + histogram_suffix) {} |
| ImportantFileWriter::ImportantFileWriter( |
| const FilePath& path, |
| scoped_refptr<SequencedTaskRunner> task_runner, |
| - TimeDelta interval) |
| + TimeDelta interval, |
| + StringPiece histogram_suffix) |
| : path_(path), |
| task_runner_(std::move(task_runner)), |
| serializer_(nullptr), |
| commit_interval_(interval), |
| + histogram_suffix_(histogram_suffix), |
| weak_factory_(this) { |
| DCHECK(task_runner_); |
| } |
| @@ -178,7 +251,7 @@ void ImportantFileWriter::WriteNow(std::unique_ptr<std::string> data) { |
| Closure task = AdaptCallbackForRepeating( |
| BindOnce(&WriteScopedStringToFileAtomically, path_, std::move(data), |
| std::move(before_next_write_callback_), |
| - std::move(after_next_write_callback_))); |
| + std::move(after_next_write_callback_), histogram_suffix_)); |
| if (!task_runner_->PostTask(FROM_HERE, MakeCriticalClosure(task))) { |
| // Posting the task to background message loop is not expected |