Index: chrome/browser/visitedlink/visitedlink_master.cc |
=================================================================== |
--- chrome/browser/visitedlink/visitedlink_master.cc (revision 148849) |
+++ chrome/browser/visitedlink/visitedlink_master.cc (working copy) |
@@ -64,6 +64,12 @@ |
memcpy(salt, &randval, 8); |
} |
+// Opens file on a background thread to not block UI thread. |
+void AsyncOpen(FILE** file, FilePath filename) { |
+ *file = OpenFile(filename, "wb+"); |
+ DLOG_IF(ERROR, !(*file)) << "Failed to open file " << filename.value(); |
+} |
+ |
// Returns true if the write was complete. |
static bool WriteToFile(FILE* file, |
off_t offset, |
@@ -84,11 +90,28 @@ |
} |
// This task executes on a background thread and executes a write. This |
-// prevents us from blocking the UI thread doing I/O. |
-void AsyncWrite(FILE* file, int32 offset, const std::string& data) { |
- WriteToFile(file, offset, data.data(), data.size()); |
+// prevents us from blocking the UI thread doing I/O. Double pointer to FILE |
+// is used because file may still not be opened by the time of scheduling |
+// the task for execution. |
+void AsyncWrite(FILE** file, int32 offset, const std::string& data) { |
+ WriteToFile(*file, offset, data.data(), data.size()); |
} |
+// Truncates the file to the current position asynchronously on a background |
+// thread. Double pointer to FILE is used because file may still not be opened |
+// by the time of scheduling the task for execution. |
+void AsyncTruncate(FILE** file) { |
+ base::IgnoreResult(TruncateFile(*file)); |
+} |
+ |
+// Closes the file on a background thread and releases memory used for storage |
+// of FILE* value. Double pointer to FILE is used because file may still not |
+// be opened by the time of scheduling the task for execution. |
+void AsyncClose(FILE** file) { |
+ base::IgnoreResult(fclose(*file)); |
+ free(file); |
+} |
+ |
} // namespace |
// TableBuilder --------------------------------------------------------------- |
@@ -178,6 +201,8 @@ |
table_builder_->DisownMaster(); |
} |
FreeURLTable(); |
+ // FreeURLTable() will schedule closing of the file and deletion of |file_|. |
+ // So nothing should be done here. |
} |
void VisitedLinkMaster::InitMembers(Listener* listener, Profile* profile) { |
@@ -455,7 +480,7 @@ |
return true; |
} |
-bool VisitedLinkMaster::WriteFullTable() { |
+void VisitedLinkMaster::WriteFullTable() { |
// This function can get called when the file is open, for example, when we |
// resize the table. We must handle this case and not try to reopen the file, |
// since there may be write operations pending on the file I/O thread. |
@@ -469,13 +494,10 @@ |
// that the file size is different when we load it back in, and then we will |
// regenerate the table. |
if (!file_) { |
+ file_ = static_cast<FILE**>(calloc(1, sizeof(*file_))); |
FilePath filename; |
GetDatabaseFileName(&filename); |
- file_ = OpenFile(filename, "wb+"); |
- if (!file_) { |
- DLOG(ERROR) << "Failed to open file " << filename.value(); |
- return false; |
- } |
+ PostIOTask(FROM_HERE, base::Bind(&AsyncOpen, file_, filename)); |
} |
// Write the new header. |
@@ -492,8 +514,7 @@ |
hash_table_, table_length_ * sizeof(Fingerprint)); |
// The hash table may have shrunk, so make sure this is the end. |
- PostIOTask(FROM_HERE, base::Bind(base::IgnoreResult(&TruncateFile), file_)); |
- return true; |
+ PostIOTask(FROM_HERE, base::Bind(&AsyncTruncate, file_)); |
} |
bool VisitedLinkMaster::InitFromFile() { |
@@ -523,7 +544,8 @@ |
DebugValidate(); |
#endif |
- file_ = file_closer.release(); |
+ file_ = static_cast<FILE**>(malloc(sizeof(*file_))); |
+ *file_ = file_closer.release(); |
return true; |
} |
@@ -545,7 +567,8 @@ |
if (suppress_rebuild) { |
// When we disallow rebuilds (normally just unit tests), just use the |
// current empty table. |
- return WriteFullTable(); |
+ WriteFullTable(); |
+ return true; |
} |
// This will build the table from history. On the first run, history will |
@@ -682,7 +705,9 @@ |
} |
if (!file_) |
return; |
- PostIOTask(FROM_HERE, base::Bind(base::IgnoreResult(&fclose), file_)); |
+ PostIOTask(FROM_HERE, base::Bind(&AsyncClose, file_)); |
+ // AsyncClose() will close the file and free the memory pointed by |file_|. |
+ file_ = NULL; |
} |
bool VisitedLinkMaster::ResizeTableIfNecessary() { |
@@ -837,10 +862,6 @@ |
AddFingerprint(*i, false); |
added_since_rebuild_.clear(); |
- // We shouldn't be writing the table from the main thread! |
- // http://code.google.com/p/chromium/issues/detail?id=24163 |
- base::ThreadRestrictions::ScopedAllowIO allow_io; |
- |
// Now handle deletions. |
DeleteFingerprintsFromCurrentTable(deleted_since_rebuild_); |
deleted_since_rebuild_.clear(); |
@@ -860,7 +881,7 @@ |
} |
} |
-void VisitedLinkMaster::WriteToFile(FILE* file, |
+void VisitedLinkMaster::WriteToFile(FILE** file, |
off_t offset, |
void* data, |
int32 data_size) { |