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..25626abdee134766b33dc3fa53a998fe57100fb4 100644 |
| --- a/base/files/important_file_writer.cc |
| +++ b/base/files/important_file_writer.cc |
| @@ -49,10 +49,35 @@ 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 |
| +// HistogramBase::Sample. |
| +template <typename SampleType> |
| +typename std::enable_if< |
| + std::is_convertible<SampleType, HistogramBase::Sample>::value>::type |
| +DynamicUmaHistogramEnumeration(const char* histogram_name, |
|
rkaplow
2017/06/05 18:17:30
can you use the function version from https://cs.c
xaerox
2017/06/07 09:32:54
Acknowledged.
|
| + const std::string& histogram_suffix, |
| + SampleType add_sample, |
| + SampleType max_sample) { |
| + constexpr auto one_sample = HistogramBase::Sample(1); |
| + const auto histogram_full_name = |
| + std::string(histogram_name).append(histogram_suffix); |
| + auto* histogram = Histogram::FactoryGet( |
| + histogram_full_name, one_sample, |
| + static_cast<HistogramBase::Sample>(max_sample), |
| + static_cast<HistogramBase::Sample>(max_sample) + one_sample, |
| + HistogramBase::kUmaTargetedHistogramFlag); |
| + if (histogram) |
| + histogram->Add(static_cast<HistogramBase::Sample>(add_sample)); |
| +} |
| + |
| +void LogFailure(const FilePath& path, |
| + const std::string& histogram_suffix, |
| + TempFileFailure failure_code, |
| StringPiece message) { |
| - UMA_HISTOGRAM_ENUMERATION("ImportantFile.TempFileFailures", failure_code, |
| - TEMP_FILE_FAILURE_MAX); |
| + DynamicUmaHistogramEnumeration("ImportantFile.TempFileFailures", |
| + histogram_suffix, failure_code, |
| + TEMP_FILE_FAILURE_MAX); |
| DPLOG(WARNING) << "temp file failure: " << path.value() << " : " << message; |
| } |
| @@ -62,21 +87,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, |
| + 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, std::move(histogram_suffix)); |
| 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, |
| + const std::string& histogram_suffix) { |
| + if (!DeleteFile(tmp_file_path, false)) { |
| + DynamicUmaHistogramEnumeration("ImportantFile.FileDeleteError", |
| + histogram_suffix, -GetLastFileError(), |
| + -base::File::FILE_ERROR_MAX); |
| + } |
| +} |
| + |
| } // namespace |
| // static |
| bool ImportantFileWriter::WriteFileAtomically(const FilePath& path, |
| - StringPiece data) { |
| + StringPiece data, |
| + std::string 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 +144,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"); |
| + DynamicUmaHistogramEnumeration("ImportantFile.FileCreateError", |
| + histogram_suffix, -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"); |
| + DynamicUmaHistogramEnumeration("ImportantFile.FileOpenError", |
| + histogram_suffix, -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 +166,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) { |
| + DynamicUmaHistogramEnumeration("ImportantFile.FileWriteError", |
| + histogram_suffix, -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); |
| 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)) { |
| + DynamicUmaHistogramEnumeration("ImportantFile.FileRenameError", |
| + histogram_suffix, -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 +203,23 @@ bool ImportantFileWriter::WriteFileAtomically(const FilePath& path, |
| ImportantFileWriter::ImportantFileWriter( |
| const FilePath& path, |
| - scoped_refptr<SequencedTaskRunner> task_runner) |
| + scoped_refptr<SequencedTaskRunner> task_runner, |
| + std::string histogram_suffix) |
| : ImportantFileWriter(path, |
| std::move(task_runner), |
| - kDefaultCommitInterval) {} |
| + kDefaultCommitInterval, |
| + std::move(histogram_suffix)) {} |
| ImportantFileWriter::ImportantFileWriter( |
| const FilePath& path, |
| scoped_refptr<SequencedTaskRunner> task_runner, |
| - TimeDelta interval) |
| + TimeDelta interval, |
| + std::string histogram_suffix) |
| : path_(path), |
| task_runner_(std::move(task_runner)), |
| serializer_(nullptr), |
| commit_interval_(interval), |
| + histogram_suffix_(std::move(histogram_suffix)), |
| weak_factory_(this) { |
| DCHECK(task_runner_); |
| } |
| @@ -178,7 +247,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 |