Commit 1ad9bfe4 authored by hashimoto's avatar hashimoto Committed by Commit bot

Avoid copying the data string when posting ImportantFileWriter write tasks

When binding the data string to a callback, the existing code copies the data which can be 1MB+ sometimes.
Use scoped_ptr to avoid unnecessary data copy.

BUG=None

Review URL: https://codereview.chromium.org/1079943002

Cr-Commit-Position: refs/heads/master@{#327234}
parent 21999efe
...@@ -51,6 +51,12 @@ void LogFailure(const FilePath& path, TempFileFailure failure_code, ...@@ -51,6 +51,12 @@ void LogFailure(const FilePath& path, TempFileFailure failure_code,
<< " : " << message; << " : " << message;
} }
// Helper function to call WriteFileAtomically() with a scoped_ptr<std::string>.
bool WriteScopedStringToFileAtomically(const FilePath& path,
scoped_ptr<std::string> data) {
return ImportantFileWriter::WriteFileAtomically(path, *data);
}
} // namespace } // namespace
// static // static
...@@ -139,9 +145,9 @@ bool ImportantFileWriter::HasPendingWrite() const { ...@@ -139,9 +145,9 @@ bool ImportantFileWriter::HasPendingWrite() const {
return timer_.IsRunning(); return timer_.IsRunning();
} }
void ImportantFileWriter::WriteNow(const std::string& data) { void ImportantFileWriter::WriteNow(scoped_ptr<std::string> data) {
DCHECK(CalledOnValidThread()); DCHECK(CalledOnValidThread());
if (data.length() > static_cast<size_t>(kint32max)) { if (data->length() > static_cast<size_t>(kint32max)) {
NOTREACHED(); NOTREACHED();
return; return;
} }
...@@ -149,13 +155,14 @@ void ImportantFileWriter::WriteNow(const std::string& data) { ...@@ -149,13 +155,14 @@ void ImportantFileWriter::WriteNow(const std::string& data) {
if (HasPendingWrite()) if (HasPendingWrite())
timer_.Stop(); timer_.Stop();
if (!PostWriteTask(data)) { auto task = Bind(&WriteScopedStringToFileAtomically, path_, Passed(&data));
if (!PostWriteTask(task)) {
// Posting the task to background message loop is not expected // Posting the task to background message loop is not expected
// to fail, but if it does, avoid losing data and just hit the disk // to fail, but if it does, avoid losing data and just hit the disk
// on the current thread. // on the current thread.
NOTREACHED(); NOTREACHED();
WriteFileAtomically(path_, data); task.Run();
} }
} }
...@@ -173,9 +180,9 @@ void ImportantFileWriter::ScheduleWrite(DataSerializer* serializer) { ...@@ -173,9 +180,9 @@ void ImportantFileWriter::ScheduleWrite(DataSerializer* serializer) {
void ImportantFileWriter::DoScheduledWrite() { void ImportantFileWriter::DoScheduledWrite() {
DCHECK(serializer_); DCHECK(serializer_);
std::string data; scoped_ptr<std::string> data(new std::string);
if (serializer_->SerializeData(&data)) { if (serializer_->SerializeData(data.get())) {
WriteNow(data); WriteNow(data.Pass());
} else { } else {
DLOG(WARNING) << "failed to serialize data to be saved in " DLOG(WARNING) << "failed to serialize data to be saved in "
<< path_.value().c_str(); << path_.value().c_str();
...@@ -189,7 +196,7 @@ void ImportantFileWriter::RegisterOnNextSuccessfulWriteCallback( ...@@ -189,7 +196,7 @@ void ImportantFileWriter::RegisterOnNextSuccessfulWriteCallback(
on_next_successful_write_ = on_next_successful_write; on_next_successful_write_ = on_next_successful_write;
} }
bool ImportantFileWriter::PostWriteTask(const std::string& data) { bool ImportantFileWriter::PostWriteTask(const Callback<bool()>& task) {
// TODO(gab): This code could always use PostTaskAndReplyWithResult and let // TODO(gab): This code could always use PostTaskAndReplyWithResult and let
// ForwardSuccessfulWrite() no-op if |on_next_successful_write_| is null, but // ForwardSuccessfulWrite() no-op if |on_next_successful_write_| is null, but
// PostTaskAndReply causes memory leaks in tests (crbug.com/371974) and // PostTaskAndReply causes memory leaks in tests (crbug.com/371974) and
...@@ -199,16 +206,13 @@ bool ImportantFileWriter::PostWriteTask(const std::string& data) { ...@@ -199,16 +206,13 @@ bool ImportantFileWriter::PostWriteTask(const std::string& data) {
return base::PostTaskAndReplyWithResult( return base::PostTaskAndReplyWithResult(
task_runner_.get(), task_runner_.get(),
FROM_HERE, FROM_HERE,
MakeCriticalClosure( MakeCriticalClosure(task),
Bind(&ImportantFileWriter::WriteFileAtomically, path_, data)),
Bind(&ImportantFileWriter::ForwardSuccessfulWrite, Bind(&ImportantFileWriter::ForwardSuccessfulWrite,
weak_factory_.GetWeakPtr())); weak_factory_.GetWeakPtr()));
} }
return task_runner_->PostTask( return task_runner_->PostTask(
FROM_HERE, FROM_HERE,
MakeCriticalClosure( MakeCriticalClosure(base::Bind(IgnoreResult(task))));
Bind(IgnoreResult(&ImportantFileWriter::WriteFileAtomically),
path_, data)));
} }
void ImportantFileWriter::ForwardSuccessfulWrite(bool result) { void ImportantFileWriter::ForwardSuccessfulWrite(bool result) {
......
...@@ -78,7 +78,7 @@ class BASE_EXPORT ImportantFileWriter : public NonThreadSafe { ...@@ -78,7 +78,7 @@ class BASE_EXPORT ImportantFileWriter : public NonThreadSafe {
// Save |data| to target filename. Does not block. If there is a pending write // Save |data| to target filename. Does not block. If there is a pending write
// scheduled by ScheduleWrite, it is cancelled. // scheduled by ScheduleWrite, it is cancelled.
void WriteNow(const std::string& data); void WriteNow(scoped_ptr<std::string> data);
// Schedule a save to target filename. Data will be serialized and saved // Schedule a save to target filename. Data will be serialized and saved
// to disk after the commit interval. If another ScheduleWrite is issued // to disk after the commit interval. If another ScheduleWrite is issued
...@@ -106,7 +106,7 @@ class BASE_EXPORT ImportantFileWriter : public NonThreadSafe { ...@@ -106,7 +106,7 @@ class BASE_EXPORT ImportantFileWriter : public NonThreadSafe {
private: private:
// Helper method for WriteNow(). // Helper method for WriteNow().
bool PostWriteTask(const std::string& data); bool PostWriteTask(const Callback<bool()>& task);
// If |result| is true and |on_next_successful_write_| is set, invokes // If |result| is true and |on_next_successful_write_| is set, invokes
// |on_successful_write_| and then resets it; no-ops otherwise. // |on_successful_write_| and then resets it; no-ops otherwise.
......
...@@ -100,7 +100,7 @@ TEST_F(ImportantFileWriterTest, Basic) { ...@@ -100,7 +100,7 @@ TEST_F(ImportantFileWriterTest, Basic) {
ImportantFileWriter writer(file_, MessageLoopProxy::current().get()); ImportantFileWriter writer(file_, MessageLoopProxy::current().get());
EXPECT_FALSE(PathExists(writer.path())); EXPECT_FALSE(PathExists(writer.path()));
EXPECT_FALSE(successful_write_observer_.GetAndResetObservationState()); EXPECT_FALSE(successful_write_observer_.GetAndResetObservationState());
writer.WriteNow("foo"); writer.WriteNow(make_scoped_ptr(new std::string("foo")));
RunLoop().RunUntilIdle(); RunLoop().RunUntilIdle();
EXPECT_FALSE(successful_write_observer_.GetAndResetObservationState()); EXPECT_FALSE(successful_write_observer_.GetAndResetObservationState());
...@@ -113,7 +113,7 @@ TEST_F(ImportantFileWriterTest, BasicWithSuccessfulWriteObserver) { ...@@ -113,7 +113,7 @@ TEST_F(ImportantFileWriterTest, BasicWithSuccessfulWriteObserver) {
EXPECT_FALSE(PathExists(writer.path())); EXPECT_FALSE(PathExists(writer.path()));
EXPECT_FALSE(successful_write_observer_.GetAndResetObservationState()); EXPECT_FALSE(successful_write_observer_.GetAndResetObservationState());
successful_write_observer_.ObserveNextSuccessfulWrite(&writer); successful_write_observer_.ObserveNextSuccessfulWrite(&writer);
writer.WriteNow("foo"); writer.WriteNow(make_scoped_ptr(new std::string("foo")));
RunLoop().RunUntilIdle(); RunLoop().RunUntilIdle();
// Confirm that the observer is invoked. // Confirm that the observer is invoked.
...@@ -124,7 +124,7 @@ TEST_F(ImportantFileWriterTest, BasicWithSuccessfulWriteObserver) { ...@@ -124,7 +124,7 @@ TEST_F(ImportantFileWriterTest, BasicWithSuccessfulWriteObserver) {
// Confirm that re-installing the observer works for another write. // Confirm that re-installing the observer works for another write.
EXPECT_FALSE(successful_write_observer_.GetAndResetObservationState()); EXPECT_FALSE(successful_write_observer_.GetAndResetObservationState());
successful_write_observer_.ObserveNextSuccessfulWrite(&writer); successful_write_observer_.ObserveNextSuccessfulWrite(&writer);
writer.WriteNow("bar"); writer.WriteNow(make_scoped_ptr(new std::string("bar")));
RunLoop().RunUntilIdle(); RunLoop().RunUntilIdle();
EXPECT_TRUE(successful_write_observer_.GetAndResetObservationState()); EXPECT_TRUE(successful_write_observer_.GetAndResetObservationState());
...@@ -134,7 +134,7 @@ TEST_F(ImportantFileWriterTest, BasicWithSuccessfulWriteObserver) { ...@@ -134,7 +134,7 @@ TEST_F(ImportantFileWriterTest, BasicWithSuccessfulWriteObserver) {
// Confirm that writing again without re-installing the observer doesn't // Confirm that writing again without re-installing the observer doesn't
// result in a notification. // result in a notification.
EXPECT_FALSE(successful_write_observer_.GetAndResetObservationState()); EXPECT_FALSE(successful_write_observer_.GetAndResetObservationState());
writer.WriteNow("baz"); writer.WriteNow(make_scoped_ptr(new std::string("baz")));
RunLoop().RunUntilIdle(); RunLoop().RunUntilIdle();
EXPECT_FALSE(successful_write_observer_.GetAndResetObservationState()); EXPECT_FALSE(successful_write_observer_.GetAndResetObservationState());
......
...@@ -205,10 +205,10 @@ bool BookmarkStorage::SaveNow() { ...@@ -205,10 +205,10 @@ bool BookmarkStorage::SaveNow() {
return false; return false;
} }
std::string data; scoped_ptr<std::string> data(new std::string);
if (!SerializeData(&data)) if (!SerializeData(data.get()))
return false; return false;
writer_.WriteNow(data); writer_.WriteNow(data.Pass());
return true; return true;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment