Prepopulate directory database for isolated origins

This reduces end-to-end OpenFileSystem + CreateFile cost
by ~100ms (measured in JS layer) for packaged apps.

BUG=242272
[email protected]

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@203877 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/webkit/browser/fileapi/obfuscated_file_util.cc b/webkit/browser/fileapi/obfuscated_file_util.cc
index f976985..00662f76 100644
--- a/webkit/browser/fileapi/obfuscated_file_util.cc
+++ b/webkit/browser/fileapi/obfuscated_file_util.cc
@@ -991,6 +991,36 @@
   return UsageForPath(VirtualPath::BaseName(path).value().size());
 }
 
+void ObfuscatedFileUtil::MaybePrepopulateDatabase() {
+  base::FilePath isolated_origin_dir = file_system_directory_.Append(
+      SandboxIsolatedOriginDatabase::kOriginDirectory);
+  if (!file_util::DirectoryExists(isolated_origin_dir))
+    return;
+
+  const FileSystemType kPrepopulateTypes[] = {
+    kFileSystemTypePersistent, kFileSystemTypeTemporary
+  };
+
+  // Prepulate the directory database(s) if and only if this instance is
+  // initialized for isolated storage dedicated for a single origin.
+  for (size_t i = 0; i < arraysize(kPrepopulateTypes); ++i) {
+    const FileSystemType type = kPrepopulateTypes[i];
+    base::FilePath::StringType type_string = GetDirectoryNameForType(type);
+    DCHECK(!type_string.empty());
+    base::FilePath path = isolated_origin_dir.Append(type_string);
+    if (!file_util::DirectoryExists(path))
+      continue;
+    scoped_ptr<SandboxDirectoryDatabase> db(new SandboxDirectoryDatabase(path));
+    if (db->Init(SandboxDirectoryDatabase::FAIL_ON_CORRUPTION)) {
+      directories_[GetFileSystemTypeString(type)] = db.release();
+      MarkUsed();
+      // Don't populate more than one database, as it may rather hurt
+      // performance.
+      break;
+    }
+  }
+}
+
 PlatformFileError ObfuscatedFileUtil::GetFileInfoInternal(
     SandboxDirectoryDatabase* db,
     FileSystemOperationContext* context,
@@ -1132,20 +1162,32 @@
   return root.Append(data_path);
 }
 
+std::string ObfuscatedFileUtil::GetDirectoryDatabaseKey(
+    const GURL& origin, FileSystemType type) {
+  std::string type_string = GetFileSystemTypeString(type);
+  if (type_string.empty()) {
+    LOG(WARNING) << "Unknown filesystem type requested:" << type;
+    return std::string();
+  }
+  // For isolated origin we just use a type string as a key.
+  if (special_storage_policy_ &&
+      special_storage_policy_->HasIsolatedStorage(origin)) {
+    return type_string;
+  }
+  return UTF16ToUTF8(webkit_base::GetOriginIdentifierFromURL(origin)) +
+      type_string;
+}
+
 // TODO(ericu): How to do the whole validation-without-creation thing?
 // We may not have quota even to create the database.
 // Ah, in that case don't even get here?
 // Still doesn't answer the quota issue, though.
 SandboxDirectoryDatabase* ObfuscatedFileUtil::GetDirectoryDatabase(
     const GURL& origin, FileSystemType type, bool create) {
-  std::string type_string = GetFileSystemTypeString(type);
-  if (type_string.empty()) {
-    LOG(WARNING) << "Unknown filesystem type requested:" << type;
+  std::string key = GetDirectoryDatabaseKey(origin, type);
+  if (key.empty())
     return NULL;
-  }
-  std::string key =
-      UTF16ToUTF8(webkit_base::GetOriginIdentifierFromURL(origin)) +
-      type_string;
+
   DirectoryMap::iterator iter = directories_.find(key);
   if (iter != directories_.end()) {
     MarkUsed();
@@ -1169,10 +1211,10 @@
     const GURL& origin, bool create, base::PlatformFileError* error_code) {
   if (special_storage_policy_.get() &&
       special_storage_policy_->HasIsolatedStorage(origin)) {
-    CHECK(isolated_origin_.is_empty() || isolated_origin_ == origin)
-        << "multiple origins for an isolated site: "
-        << isolated_origin_.spec() << " vs " << origin.spec();
-    isolated_origin_ = origin;
+    if (isolated_origin_.is_empty())
+      isolated_origin_ = origin;
+    CHECK_EQ(isolated_origin_.spec(), origin.spec())
+        << "multiple origins for an isolated site";
   }
 
   if (!InitOriginDatabase(create)) {