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 |