diff options
Diffstat (limited to 'webkit/appcache')
-rw-r--r-- | webkit/appcache/appcache.cc | 78 | ||||
-rw-r--r-- | webkit/appcache/appcache.h | 18 | ||||
-rw-r--r-- | webkit/appcache/appcache_database.cc | 879 | ||||
-rw-r--r-- | webkit/appcache/appcache_database.h | 159 | ||||
-rw-r--r-- | webkit/appcache/appcache_database_unittest.cc | 439 | ||||
-rw-r--r-- | webkit/appcache/appcache_group_unittest.cc | 5 | ||||
-rw-r--r-- | webkit/appcache/appcache_host.cc | 2 | ||||
-rw-r--r-- | webkit/appcache/appcache_host.h | 5 | ||||
-rw-r--r-- | webkit/appcache/appcache_storage_impl.cc | 856 | ||||
-rw-r--r-- | webkit/appcache/appcache_storage_impl.h | 92 | ||||
-rw-r--r-- | webkit/appcache/appcache_storage_impl_unittest.cc | 1007 | ||||
-rw-r--r-- | webkit/appcache/appcache_thread.h | 10 | ||||
-rw-r--r-- | webkit/appcache/appcache_working_set.cc | 13 | ||||
-rw-r--r-- | webkit/appcache/appcache_working_set.h | 15 | ||||
-rw-r--r-- | webkit/appcache/mock_appcache_storage.cc | 12 |
15 files changed, 25 insertions, 3565 deletions
diff --git a/webkit/appcache/appcache.cc b/webkit/appcache/appcache.cc index ec00cc4..38d3228 100644 --- a/webkit/appcache/appcache.cc +++ b/webkit/appcache/appcache.cc @@ -79,84 +79,6 @@ void AppCache::InitializeWithManifest(Manifest* manifest) { SortByLength); } -void AppCache::InitializeWithDatabaseRecords( - const AppCacheDatabase::CacheRecord& cache_record, - const std::vector<AppCacheDatabase::EntryRecord>& entries, - const std::vector<AppCacheDatabase::FallbackNameSpaceRecord>& fallbacks, - const std::vector<AppCacheDatabase::OnlineWhiteListRecord>& whitelists) { - DCHECK(cache_id_ == cache_record.cache_id); - online_whitelist_all_ = cache_record.online_wildcard; - update_time_ = cache_record.update_time; - - for (size_t i = 0; i < entries.size(); ++i) { - const AppCacheDatabase::EntryRecord& entry = entries.at(i); - AddEntry(entry.url, AppCacheEntry(entry.flags, entry.response_id)); - } - - for (size_t i = 0; i < fallbacks.size(); ++i) { - const AppCacheDatabase::FallbackNameSpaceRecord& fallback = fallbacks.at(i); - fallback_namespaces_.push_back( - FallbackNamespace(fallback.namespace_url, fallback.fallback_entry_url)); - } - - // Sort the fallback namespaces by url string length, longest to shortest, - // since longer matches trump when matching a url to a namespace. - std::sort(fallback_namespaces_.begin(), fallback_namespaces_.end(), - SortByLength); - - if (!online_whitelist_all_) { - for (size_t i = 0; i < whitelists.size(); ++i) { - online_whitelist_namespaces_.push_back(whitelists.at(i).namespace_url); - } - } -} - -void AppCache::ToDatabaseRecords( - const AppCacheGroup* group, - AppCacheDatabase::CacheRecord* cache_record, - std::vector<AppCacheDatabase::EntryRecord>* entries, - std::vector<AppCacheDatabase::FallbackNameSpaceRecord>* fallbacks, - std::vector<AppCacheDatabase::OnlineWhiteListRecord>* whitelists) { - DCHECK(group && cache_record && entries && fallbacks && whitelists); - DCHECK(entries->empty() && fallbacks->empty() && whitelists->empty()); - - cache_record->cache_id = cache_id_; - cache_record->group_id = group->group_id(); - cache_record->online_wildcard = online_whitelist_all_; - cache_record->update_time = update_time_; - - for (EntryMap::const_iterator iter = entries_.begin(); - iter != entries_.end(); ++iter) { - entries->push_back(AppCacheDatabase::EntryRecord()); - AppCacheDatabase::EntryRecord& record = entries->back(); - record.url = iter->first; - record.cache_id = cache_id_; - record.flags = iter->second.types(); - record.response_id = iter->second.response_id(); - } - - GURL origin = group->manifest_url().GetOrigin(); - - for (size_t i = 0; i < fallback_namespaces_.size(); ++i) { - fallbacks->push_back(AppCacheDatabase::FallbackNameSpaceRecord()); - AppCacheDatabase::FallbackNameSpaceRecord& record = fallbacks->back(); - record.cache_id = cache_id_; - record.origin = origin; - record.namespace_url = fallback_namespaces_[i].first; - record.fallback_entry_url = fallback_namespaces_[i].second; - } - - if (!online_whitelist_all_) { - for (size_t i = 0; i < online_whitelist_namespaces_.size(); ++i) { - whitelists->push_back(AppCacheDatabase::OnlineWhiteListRecord()); - AppCacheDatabase::OnlineWhiteListRecord& record = whitelists->back(); - record.cache_id = cache_id_; - record.namespace_url = online_whitelist_namespaces_[i]; - } - } -} - - bool AppCache::FindResponseForRequest(const GURL& url, AppCacheEntry* found_entry, AppCacheEntry* found_fallback_entry, GURL* found_fallback_namespace, bool* found_network_namespace) { diff --git a/webkit/appcache/appcache.h b/webkit/appcache/appcache.h index c4446f9..6e43a85 100644 --- a/webkit/appcache/appcache.h +++ b/webkit/appcache/appcache.h @@ -14,7 +14,6 @@ #include "base/time.h" #include "googleurl/src/gurl.h" #include "testing/gtest/include/gtest/gtest_prod.h" -#include "webkit/appcache/appcache_database.h" #include "webkit/appcache/appcache_entry.h" #include "webkit/appcache/manifest_parser.h" @@ -76,22 +75,6 @@ class AppCache : public base::RefCounted<AppCache> { // Do not use the manifest after this call. void InitializeWithManifest(Manifest* manifest); - // Initializes the cache with the information in the database records. - void InitializeWithDatabaseRecords( - const AppCacheDatabase::CacheRecord& cache_record, - const std::vector<AppCacheDatabase::EntryRecord>& entries, - const std::vector<AppCacheDatabase::FallbackNameSpaceRecord>& fallbacks, - const std::vector<AppCacheDatabase::OnlineWhiteListRecord>& whitelists); - - // Returns the database records to be stored in the AppCacheDatabase - // to represent this cache. - void ToDatabaseRecords( - const AppCacheGroup* group, - AppCacheDatabase::CacheRecord* cache_record, - std::vector<AppCacheDatabase::EntryRecord>* entries, - std::vector<AppCacheDatabase::FallbackNameSpaceRecord>* fallbacks, - std::vector<AppCacheDatabase::OnlineWhiteListRecord>* whitelists); - bool FindResponseForRequest(const GURL& url, AppCacheEntry* found_entry, AppCacheEntry* found_fallback_entry, GURL* found_fallback_namespace, bool* found_network_namespace); @@ -99,7 +82,6 @@ class AppCache : public base::RefCounted<AppCache> { private: friend class AppCacheGroup; friend class AppCacheHost; - friend class AppCacheStorageImplTest; friend class AppCacheUpdateJobTest; friend class base::RefCounted<AppCache>; diff --git a/webkit/appcache/appcache_database.cc b/webkit/appcache/appcache_database.cc deleted file mode 100644 index 256def1..0000000 --- a/webkit/appcache/appcache_database.cc +++ /dev/null @@ -1,879 +0,0 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "webkit/appcache/appcache_database.h" - -#include "app/sql/connection.h" -#include "app/sql/meta_table.h" -#include "app/sql/statement.h" -#include "app/sql/transaction.h" -#include "base/auto_reset.h" -#include "base/file_util.h" -#include "base/logging.h" -#include "webkit/appcache/appcache_entry.h" - -// Schema ------------------------------------------------------------------- -namespace { - -const int kCurrentVersion = 0; -const int kCompatibleVersion = 0; - -const char* kGroupsTable = "Groups"; -const char* kCachesTable = "Caches"; -const char* kEntriesTable = "Entries"; -const char* kFallbackNameSpacesTable = "FallbackNameSpaces"; -const char* kOnlineWhiteListsTable = "OnlineWhiteLists"; - -const struct { - const char* table_name; - const char* columns; -} kTables[] = { - { kGroupsTable, - "(group_id INTEGER PRIMARY KEY," - " origin TEXT," - " manifest_url TEXT)" }, - - { kCachesTable, - "(cache_id INTEGER PRIMARY KEY," - " group_id INTEGER," - " online_wildcard INTEGER CHECK(online_wildcard IN (0, 1))," - " update_time INTEGER)" }, - - { kEntriesTable, - "(cache_id INTEGER," - " url TEXT," - " flags INTEGER," - " response_id INTEGER)" }, - - { kFallbackNameSpacesTable, - "(cache_id INTEGER," - " origin TEXT," // intentionally not normalized - " namespace_url TEXT," - " fallback_entry_url TEXT)" }, - - { kOnlineWhiteListsTable, - "(cache_id INTEGER," - " namespace_url TEXT)" }, -}; - -const struct { - const char* index_name; - const char* table_name; - const char* columns; - bool unique; -} kIndexes[] = { - { "GroupsOriginIndex", - kGroupsTable, - "(origin)", - false }, - - { "GroupsManifestIndex", - kGroupsTable, - "(manifest_url)", - true }, - - { "CachesGroupIndex", - kCachesTable, - "(group_id)", - false }, - - { "EntriesCacheIndex", - kEntriesTable, - "(cache_id)", - false }, - - { "EntriesCacheAndUrlIndex", - kEntriesTable, - "(cache_id, url)", - true }, - - { "FallbackNameSpacesCacheIndex", - kFallbackNameSpacesTable, - "(cache_id)", - false }, - - { "FallbackNameSpacesOriginIndex", - kFallbackNameSpacesTable, - "(origin)", - false }, - - { "FallbackNameSpacesCacheAndUrlIndex", - kFallbackNameSpacesTable, - "(cache_id, namespace_url)", - true }, - - { "OnlineWhiteListCacheIndex", - kOnlineWhiteListsTable, - "(cache_id)", - false }, -}; - -const int kTableCount = ARRAYSIZE_UNSAFE(kTables); -const int kIndexCount = ARRAYSIZE_UNSAFE(kIndexes); - -} // anon namespace - - -// AppCacheDatabase ---------------------------------------------------------- -namespace appcache { - -AppCacheDatabase::AppCacheDatabase(const FilePath& path) - : db_file_path_(path), has_open_error_(false), is_recreating_(false) { -} - -AppCacheDatabase::~AppCacheDatabase() { -} - -void AppCacheDatabase::CloseConnection() { - // We can't close the connection for an in-memory database w/o - // losing all of the data, so we don't do that. - if (!db_file_path_.empty()) { - meta_table_.reset(); - db_.reset(); - } -} - -bool AppCacheDatabase::FindOriginsWithGroups(std::set<GURL>* origins) { - DCHECK(origins && origins->empty()); - if (!LazyOpen(false)) - return false; - - const char* kSql = - "SELECT DISTINCT(origin) FROM Groups"; - - sql::Statement statement; - if (!PrepareUniqueStatement(kSql, &statement)) - return false; - - while (statement.Step()) - origins->insert(GURL(statement.ColumnString(0))); - - return statement.Succeeded(); -} - -bool AppCacheDatabase::FindLastStorageIds( - int64* last_group_id, int64* last_cache_id, int64* last_response_id) { - DCHECK(last_group_id && last_cache_id && last_response_id); - - *last_group_id = 0; - *last_cache_id = 0; - *last_response_id = 0; - - if (!LazyOpen(false)) - return false; - - sql::Statement statement; - - const char* kSql1 = "SELECT MAX(group_id) FROM Groups"; - if (!PrepareUniqueStatement(kSql1, &statement) || - !statement.Step()) { - return false; - } - int64 group_id = statement.ColumnInt64(0); - - const char* kSql2 = "SELECT MAX(cache_id) FROM Caches"; - if (!PrepareUniqueStatement(kSql2, &statement) || - !statement.Step()) { - return false; - } - int64 cache_id = statement.ColumnInt64(0); - - // TODO(michaeln): SELECT MAX(responseId) FROM Where/How ? - int64 response_id = 0; - - *last_group_id = group_id; - *last_cache_id = cache_id; - *last_response_id = response_id; - return true; -} - -bool AppCacheDatabase::FindGroup(int64 group_id, GroupRecord* record) { - DCHECK(record); - if (!LazyOpen(false)) - return false; - - const char* kSql = - "SELECT group_id, origin, manifest_url FROM Groups WHERE group_id = ?"; - - sql::Statement statement; - if (!PrepareCachedStatement(SQL_FROM_HERE, kSql, &statement)) - return false; - - statement.BindInt64(0, group_id); - if (!statement.Step() || !statement.Succeeded()) - return false; - - ReadGroupRecord(statement, record); - DCHECK(record->group_id == group_id); - return true; -} - -bool AppCacheDatabase::FindGroupForManifestUrl( - const GURL& manifest_url, GroupRecord* record) { - DCHECK(record); - if (!LazyOpen(false)) - return false; - - const char* kSql = - "SELECT group_id, origin, manifest_url FROM Groups" - " WHERE manifest_url = ?"; - - sql::Statement statement; - if (!PrepareCachedStatement(SQL_FROM_HERE, kSql, &statement)) - return false; - - statement.BindString(0, manifest_url.spec()); - if (!statement.Step() || !statement.Succeeded()) - return false; - - ReadGroupRecord(statement, record); - DCHECK(record->manifest_url == manifest_url); - return true; -} - -bool AppCacheDatabase::FindGroupsForOrigin( - const GURL& origin, std::vector<GroupRecord>* records) { - DCHECK(records && records->empty()); - if (!LazyOpen(false)) - return false; - - const char* kSql = - "SELECT group_id, origin, manifest_url FROM Groups WHERE origin = ?"; - - sql::Statement statement; - if (!PrepareCachedStatement(SQL_FROM_HERE, kSql, &statement)) - return false; - - statement.BindString(0, origin.spec()); - while (statement.Step()) { - records->push_back(GroupRecord()); - ReadGroupRecord(statement, &records->back()); - DCHECK(records->back().origin == origin); - } - - return statement.Succeeded(); -} - -bool AppCacheDatabase::FindGroupForCache(int64 cache_id, GroupRecord* record) { - DCHECK(record); - if (!LazyOpen(false)) - return false; - - const char* kSql = - "SELECT g.group_id, g.origin, g.manifest_url FROM Groups g, Caches c" - " WHERE c.cache_id = ? AND c.group_id = g.group_id"; - - sql::Statement statement; - if (!PrepareCachedStatement(SQL_FROM_HERE, kSql, &statement)) - return false; - - statement.BindInt64(0, cache_id); - if (!statement.Step() || !statement.Succeeded()) - return false; - - ReadGroupRecord(statement, record); - return true; -} - -bool AppCacheDatabase::InsertGroup(const GroupRecord* record) { - if (!LazyOpen(true)) - return false; - - const char* kSql = - "INSERT INTO Groups (group_id, origin, manifest_url)" - " VALUES(?, ?, ?)"; - - sql::Statement statement; - if (!PrepareCachedStatement(SQL_FROM_HERE, kSql, &statement)) - return false; - - statement.BindInt64(0, record->group_id); - statement.BindString(1, record->origin.spec()); - statement.BindString(2, record->manifest_url.spec()); - return statement.Run(); -} - -bool AppCacheDatabase::DeleteGroup(int64 group_id) { - if (!LazyOpen(false)) - return false; - - const char* kSql = - "DELETE FROM Groups WHERE group_id = ?"; - - sql::Statement statement; - if (!PrepareCachedStatement(SQL_FROM_HERE, kSql, &statement)) - return false; - - statement.BindInt64(0, group_id); - return statement.Run(); -} - -bool AppCacheDatabase::FindCache(int64 cache_id, CacheRecord* record) { - DCHECK(record); - if (!LazyOpen(false)) - return false; - - const char* kSql = - "SELECT cache_id, group_id, online_wildcard, update_time" - " FROM Caches WHERE cache_id = ?"; - - sql::Statement statement; - if (!PrepareCachedStatement(SQL_FROM_HERE, kSql, &statement)) - return false; - - statement.BindInt64(0, cache_id); - if (!statement.Step() || !statement.Succeeded()) - return false; - - ReadCacheRecord(statement, record); - return true; -} - -bool AppCacheDatabase::FindCacheForGroup(int64 group_id, CacheRecord* record) { - DCHECK(record); - if (!LazyOpen(false)) - return false; - - const char* kSql = - "SELECT cache_id, group_id, online_wildcard, update_time" - " FROM Caches WHERE group_id = ?"; - - sql::Statement statement; - if (!PrepareCachedStatement(SQL_FROM_HERE, kSql, &statement)) - return false; - - statement.BindInt64(0, group_id); - if (!statement.Step() || !statement.Succeeded()) - return false; - - ReadCacheRecord(statement, record); - return true; -} - -bool AppCacheDatabase::InsertCache(const CacheRecord* record) { - if (!LazyOpen(true)) - return false; - - const char* kSql = - "INSERT INTO Caches (cache_id, group_id, online_wildcard," - " update_time)" - " VALUES(?, ?, ?, ?)"; - - sql::Statement statement; - if (!PrepareCachedStatement(SQL_FROM_HERE, kSql, &statement)) - return false; - - statement.BindInt64(0, record->cache_id); - statement.BindInt64(1, record->group_id); - statement.BindBool(2, record->online_wildcard); - - // There are no convinient methods to convert TimeTicks to or - // from microseconds directly, so we compute TimeDelta's - // as an intermediary step. - statement.BindInt64(3, - (record->update_time - base::TimeTicks()).InMicroseconds()); - - return statement.Run(); -} - -bool AppCacheDatabase::DeleteCache(int64 cache_id) { - if (!LazyOpen(false)) - return false; - - const char* kSql = - "DELETE FROM Caches WHERE cache_id = ?"; - - sql::Statement statement; - if (!PrepareCachedStatement(SQL_FROM_HERE, kSql, &statement)) - return false; - - statement.BindInt64(0, cache_id); - return statement.Run(); -} - -bool AppCacheDatabase::FindEntriesForCache( - int64 cache_id, std::vector<EntryRecord>* records) { - DCHECK(records && records->empty()); - if (!LazyOpen(false)) - return false; - - const char* kSql = - "SELECT cache_id, url, flags, response_id FROM Entries" - " WHERE cache_id = ?"; - - sql::Statement statement; - if (!PrepareCachedStatement(SQL_FROM_HERE, kSql, &statement)) - return false; - - statement.BindInt64(0, cache_id); - while (statement.Step()) { - records->push_back(EntryRecord()); - ReadEntryRecord(statement, &records->back()); - DCHECK(records->back().cache_id == cache_id); - } - - return statement.Succeeded(); -} - -bool AppCacheDatabase::FindEntriesForUrl( - const GURL& url, std::vector<EntryRecord>* records) { - DCHECK(records && records->empty()); - if (!LazyOpen(false)) - return false; - - const char* kSql = - "SELECT cache_id, url, flags, response_id FROM Entries" - " WHERE url = ?"; - - sql::Statement statement; - if (!PrepareCachedStatement(SQL_FROM_HERE, kSql, &statement)) - return false; - - statement.BindString(0, url.spec()); - while (statement.Step()) { - records->push_back(EntryRecord()); - ReadEntryRecord(statement, &records->back()); - DCHECK(records->back().url == url); - } - - return statement.Succeeded(); -} - - -bool AppCacheDatabase::FindEntry( - int64 cache_id, const GURL& url, EntryRecord* record) { - DCHECK(record); - if (!LazyOpen(false)) - return false; - - const char* kSql = - "SELECT cache_id, url, flags, response_id FROM Entries" - " WHERE cache_id = ? AND url = ?"; - - sql::Statement statement; - if (!PrepareCachedStatement(SQL_FROM_HERE, kSql, &statement)) - return false; - - statement.BindInt64(0, cache_id); - statement.BindString(1, url.spec()); - if (!statement.Step() || !statement.Succeeded()) - return false; - - ReadEntryRecord(statement, record); - DCHECK(record->cache_id == cache_id); - DCHECK(record->url == url); - return true; -} - -bool AppCacheDatabase::InsertEntry(const EntryRecord* record) { - if (!LazyOpen(true)) - return false; - - const char* kSql = - "INSERT INTO Entries (cache_id, url, flags, response_id)" - " VALUES(?, ?, ?, ?)"; - - sql::Statement statement; - if (!PrepareCachedStatement(SQL_FROM_HERE, kSql, &statement)) - return false; - - statement.BindInt64(0, record->cache_id); - statement.BindString(1, record->url.spec()); - statement.BindInt(2, record->flags); - statement.BindInt64(3, record->response_id); - return statement.Run(); -} - -bool AppCacheDatabase::InsertEntryRecords( - const std::vector<EntryRecord>& records) { - std::vector<EntryRecord>::const_iterator iter = records.begin(); - while (iter != records.end()) { - if (!InsertEntry(&(*iter))) - return false; - ++iter; - } - return true; -} - -bool AppCacheDatabase::DeleteEntriesForCache(int64 cache_id) { - if (!LazyOpen(false)) - return false; - - const char* kSql = - "DELETE FROM Entries WHERE cache_id = ?"; - - sql::Statement statement; - if (!PrepareCachedStatement(SQL_FROM_HERE, kSql, &statement)) - return false; - - statement.BindInt64(0, cache_id); - return statement.Run(); -} - -bool AppCacheDatabase::AddEntryFlags( - const GURL& entry_url, int64 cache_id, int additional_flags) { - if (!LazyOpen(false)) - return false; - - const char* kSql = - "UPDATE Entries SET flags = flags | ? WHERE cache_id = ? AND url = ?"; - - sql::Statement statement; - if (!PrepareCachedStatement(SQL_FROM_HERE, kSql, &statement)) - return false; - - statement.BindInt(0, additional_flags); - statement.BindInt64(1, cache_id); - statement.BindString(2, entry_url.spec()); - return statement.Run() && db_->GetLastChangeCount(); -} - -bool AppCacheDatabase::FindFallbackNameSpacesForOrigin( - const GURL& origin, std::vector<FallbackNameSpaceRecord>* records) { - DCHECK(records && records->empty()); - if (!LazyOpen(false)) - return false; - - const char* kSql = - "SELECT cache_id, origin, namespace_url, fallback_entry_url" - " FROM FallbackNameSpaces WHERE origin = ?"; - - sql::Statement statement; - if (!PrepareCachedStatement(SQL_FROM_HERE, kSql, &statement)) - return false; - - statement.BindString(0, origin.spec()); - while (statement.Step()) { - records->push_back(FallbackNameSpaceRecord()); - ReadFallbackNameSpaceRecord(statement, &records->back()); - DCHECK(records->back().origin == origin); - } - return statement.Succeeded(); -} - -bool AppCacheDatabase::FindFallbackNameSpacesForCache( - int64 cache_id, std::vector<FallbackNameSpaceRecord>* records) { - DCHECK(records && records->empty()); - if (!LazyOpen(false)) - return false; - - const char* kSql = - "SELECT cache_id, origin, namespace_url, fallback_entry_url" - " FROM FallbackNameSpaces WHERE cache_id = ?"; - - sql::Statement statement; - if (!PrepareCachedStatement(SQL_FROM_HERE, kSql, &statement)) - return false; - - statement.BindInt64(0, cache_id); - while (statement.Step()) { - records->push_back(FallbackNameSpaceRecord()); - ReadFallbackNameSpaceRecord(statement, &records->back()); - DCHECK(records->back().cache_id == cache_id); - } - return statement.Succeeded(); -} - -bool AppCacheDatabase::InsertFallbackNameSpace( - const FallbackNameSpaceRecord* record) { - if (!LazyOpen(true)) - return false; - - const char* kSql = - "INSERT INTO FallbackNameSpaces" - " (cache_id, origin, namespace_url, fallback_entry_url)" - " VALUES (?, ?, ?, ?)"; - - sql::Statement statement; - if (!PrepareCachedStatement(SQL_FROM_HERE, kSql, &statement)) - return false; - - statement.BindInt64(0, record->cache_id); - statement.BindString(1, record->origin.spec()); - statement.BindString(2, record->namespace_url.spec()); - statement.BindString(3, record->fallback_entry_url.spec()); - return statement.Run(); -} - -bool AppCacheDatabase::InsertFallbackNameSpaceRecords( - const std::vector<FallbackNameSpaceRecord>& records) { - std::vector<FallbackNameSpaceRecord>::const_iterator iter = records.begin(); - while (iter != records.end()) { - if (!InsertFallbackNameSpace(&(*iter))) - return false; - ++iter; - } - return true; -} - -bool AppCacheDatabase::DeleteFallbackNameSpacesForCache(int64 cache_id) { - if (!LazyOpen(false)) - return false; - - const char* kSql = - "DELETE FROM FallbackNameSpaces WHERE cache_id = ?"; - - sql::Statement statement; - if (!PrepareCachedStatement(SQL_FROM_HERE, kSql, &statement)) - return false; - - statement.BindInt64(0, cache_id); - return statement.Run(); -} - -bool AppCacheDatabase::FindOnlineWhiteListForCache( - int64 cache_id, std::vector<OnlineWhiteListRecord>* records) { - DCHECK(records && records->empty()); - if (!LazyOpen(false)) - return false; - - const char* kSql = - "SELECT cache_id, namespace_url FROM OnlineWhiteLists" - " WHERE cache_id = ?"; - - sql::Statement statement; - if (!PrepareCachedStatement(SQL_FROM_HERE, kSql, &statement)) - return false; - - statement.BindInt64(0, cache_id); - while (statement.Step()) { - records->push_back(OnlineWhiteListRecord()); - this->ReadOnlineWhiteListRecord(statement, &records->back()); - DCHECK(records->back().cache_id == cache_id); - } - return statement.Succeeded(); -} - -bool AppCacheDatabase::InsertOnlineWhiteList( - const OnlineWhiteListRecord* record) { - if (!LazyOpen(true)) - return false; - - const char* kSql = - "INSERT INTO OnlineWhiteLists (cache_id, namespace_url) VALUES (?, ?)"; - - sql::Statement statement; - if (!PrepareCachedStatement(SQL_FROM_HERE, kSql, &statement)) - return false; - - statement.BindInt64(0, record->cache_id); - statement.BindString(1, record->namespace_url.spec()); - return statement.Run(); -} - -bool AppCacheDatabase::InsertOnlineWhiteListRecords( - const std::vector<OnlineWhiteListRecord>& records) { - std::vector<OnlineWhiteListRecord>::const_iterator iter = records.begin(); - while (iter != records.end()) { - if (!InsertOnlineWhiteList(&(*iter))) - return false; - ++iter; - } - return true; -} - -bool AppCacheDatabase::DeleteOnlineWhiteListForCache(int64 cache_id) { - if (!LazyOpen(false)) - return false; - - const char* kSql = - "DELETE FROM OnlineWhiteLists WHERE cache_id = ?"; - - sql::Statement statement; - if (!PrepareCachedStatement(SQL_FROM_HERE, kSql, &statement)) - return false; - - statement.BindInt64(0, cache_id); - return statement.Run(); -} - -bool AppCacheDatabase::PrepareUniqueStatement( - const char* sql, sql::Statement* statement) { - DCHECK(sql && statement); - statement->Assign(db_->GetUniqueStatement(sql)); - if (!statement->is_valid()) { - NOTREACHED() << db_->GetErrorMessage(); - return false; - } - return true; -} - -bool AppCacheDatabase::PrepareCachedStatement( - const sql::StatementID& id, const char* sql, sql::Statement* statement) { - DCHECK(sql && statement); - statement->Assign(db_->GetCachedStatement(id, sql)); - if (!statement->is_valid()) { - NOTREACHED() << db_->GetErrorMessage(); - return false; - } - return true; -} - -void AppCacheDatabase::ReadGroupRecord( - const sql::Statement& statement, GroupRecord* record) { - record->group_id = statement.ColumnInt64(0); - record->origin = GURL(statement.ColumnString(1)); - record->manifest_url = GURL(statement.ColumnString(2)); -} - -void AppCacheDatabase::ReadCacheRecord( - const sql::Statement& statement, CacheRecord* record) { - record->cache_id = statement.ColumnInt64(0); - record->group_id = statement.ColumnInt64(1); - record->online_wildcard = statement.ColumnBool(2); - - // There are no convinient methods to convert TimeTicks to or - // from microseconds directly, so we compute TimeDelta's - // as an intermediary step. - record->update_time = base::TimeTicks() + - base::TimeDelta::FromMicroseconds(statement.ColumnInt64(3)); -} - -void AppCacheDatabase::ReadEntryRecord( - const sql::Statement& statement, EntryRecord* record) { - record->cache_id = statement.ColumnInt64(0); - record->url = GURL(statement.ColumnString(1)); - record->flags = statement.ColumnInt(2); - record->response_id = statement.ColumnInt64(3); -} - -void AppCacheDatabase::ReadFallbackNameSpaceRecord( - const sql::Statement& statement, FallbackNameSpaceRecord* record) { - record->cache_id = statement.ColumnInt64(0); - record->origin = GURL(statement.ColumnString(1)); - record->namespace_url = GURL(statement.ColumnString(2)); - record->fallback_entry_url = GURL(statement.ColumnString(3)); -} - -void AppCacheDatabase::ReadOnlineWhiteListRecord( - const sql::Statement& statement, OnlineWhiteListRecord* record) { - record->cache_id = statement.ColumnInt64(0); - record->namespace_url = GURL(statement.ColumnString(1)); -} - -bool AppCacheDatabase::LazyOpen(bool create_if_needed) { - if (db_.get()) - return true; - - // If we tried and failed once, don't try again in the same session - // to avoid creating an incoherent mess on disk. - if (has_open_error_) - return false; - - // Avoid creating a database at all if we can. - bool use_in_memory_db = db_file_path_.empty(); - if (!create_if_needed && - (use_in_memory_db || !file_util::PathExists(db_file_path_))) { - return false; - } - - db_.reset(new sql::Connection); - bool opened = use_in_memory_db ? db_->OpenInMemory() - : db_->Open(db_file_path_); - if (opened) - db_->Preload(); - if (!opened || !EnsureDatabaseVersion()) { - has_open_error_ = true; - meta_table_.reset(); - db_.reset(); - return false; - } - - return true; -} - -bool AppCacheDatabase::EnsureDatabaseVersion() { - bool did_create_meta_table = !sql::MetaTable::DoesTableExist(db_.get()); - - meta_table_.reset(new sql::MetaTable); - if (!meta_table_->Init(db_.get(), kCurrentVersion, kCompatibleVersion)) - return false; - - if (did_create_meta_table) - return CreateSchema(); - - if (meta_table_->GetCompatibleVersionNumber() > kCurrentVersion) { - DCHECK(!did_create_meta_table); - LOG(WARNING) << "AppCache database is too new."; - return false; - } - - if (meta_table_->GetVersionNumber() < kCurrentVersion) - return UpgradeSchema(); - -#ifndef NDEBUG - for (int i = 0; i < kTableCount; ++i) { - DCHECK(db_->DoesTableExist(kTables[i].table_name)); - } -#endif - - return true; -} - -bool AppCacheDatabase::CreateSchema() { - sql::Transaction transaction(db_.get()); - if (!transaction.Begin()) - return false; - - for (int i = 0; i < kTableCount; ++i) { - std::string sql("CREATE TABLE "); - sql += kTables[i].table_name; - sql += kTables[i].columns; - if (!db_->Execute(sql.c_str())) - return false; - } - - for (int i = 0; i < kIndexCount; ++i) { - std::string sql; - if (kIndexes[i].unique) - sql += "CREATE UNIQUE INDEX "; - else - sql += "CREATE INDEX "; - sql += kIndexes[i].index_name; - sql += " ON "; - sql += kIndexes[i].table_name; - sql += kIndexes[i].columns; - if (!db_->Execute(sql.c_str())) - return false; - } - - return transaction.Commit(); -} - -bool AppCacheDatabase::UpgradeSchema() { - DCHECK(false); // We don't have any upgrades yet since we're at version 0 - - // Upgrade logic goes here - - // If there is no upgrade path for the version on disk to the current - // version, nuke everything and start over. - return DeleteExistingAndCreateNewDatabase(); -} - -bool AppCacheDatabase::DeleteExistingAndCreateNewDatabase() { - DCHECK(!db_file_path_.empty()); - DCHECK(file_util::PathExists(db_file_path_)); - - meta_table_.reset(); - db_.reset(); - - FilePath directory = db_file_path_.DirName(); - if (!file_util::Delete(directory, true) || - !file_util::CreateDirectory(directory)) { - return false; - } - - // Make sure the steps above actually deleted things. - if (file_util::PathExists(db_file_path_)) - return false; - - // So we can't go recursive. - if (is_recreating_) - return false; - - AutoReset auto_reset(&is_recreating_, true); - return LazyOpen(true); -} - -} // namespace appcache diff --git a/webkit/appcache/appcache_database.h b/webkit/appcache/appcache_database.h deleted file mode 100644 index 89ff701..0000000 --- a/webkit/appcache/appcache_database.h +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef WEBKIT_APPCACHE_APPCACHE_DATABASE_H_ -#define WEBKIT_APPCACHE_APPCACHE_DATABASE_H_ - -#include <set> -#include <vector> - -#include "base/basictypes.h" -#include "base/file_path.h" -#include "base/scoped_ptr.h" -#include "base/time.h" -#include "googleurl/src/gurl.h" -#include "testing/gtest/include/gtest/gtest_prod.h" - -namespace sql { -class Connection; -class MetaTable; -class Statement; -class StatementID; -} - -namespace appcache { - -class AppCacheDatabase { - public: - struct GroupRecord { - int64 group_id; - GURL origin; - GURL manifest_url; - }; - - struct CacheRecord { - int64 cache_id; - int64 group_id; - bool online_wildcard; - base::TimeTicks update_time; - }; - - struct EntryRecord { - int64 cache_id; - GURL url; - int flags; - int64 response_id; - }; - - struct FallbackNameSpaceRecord { - int64 cache_id; - GURL origin; // intentionally not normalized - GURL namespace_url; - GURL fallback_entry_url; - }; - - struct OnlineWhiteListRecord { - int64 cache_id; - GURL namespace_url; - }; - - explicit AppCacheDatabase(const FilePath& path); - ~AppCacheDatabase(); - - void CloseConnection(); - bool FindOriginsWithGroups(std::set<GURL>* origins); - bool FindLastStorageIds( - int64* last_group_id, int64* last_cache_id, int64* last_response_id); - - bool FindGroup(int64 group_id, GroupRecord* record); - bool FindGroupForManifestUrl(const GURL& manifest_url, GroupRecord* record); - bool FindGroupsForOrigin( - const GURL& origin, std::vector<GroupRecord>* records); - bool FindGroupForCache(int64 cache_id, GroupRecord* record); - bool InsertGroup(const GroupRecord* record); - bool DeleteGroup(int64 group_id); - - bool FindCache(int64 cache_id, CacheRecord* record); - bool FindCacheForGroup(int64 group_id, CacheRecord* record); - bool InsertCache(const CacheRecord* record); - bool DeleteCache(int64 cache_id); - - bool FindEntriesForCache( - int64 cache_id, std::vector<EntryRecord>* records); - bool FindEntriesForUrl( - const GURL& url, std::vector<EntryRecord>* records); - bool FindEntry(int64 cache_id, const GURL& url, EntryRecord* record); - bool InsertEntry(const EntryRecord* record); - bool InsertEntryRecords( - const std::vector<EntryRecord>& records); - bool DeleteEntriesForCache(int64 cache_id); - bool AddEntryFlags(const GURL& entry_url, int64 cache_id, - int additional_flags); - - bool FindFallbackNameSpacesForOrigin( - const GURL& origin, std::vector<FallbackNameSpaceRecord>* records); - bool FindFallbackNameSpacesForCache( - int64 cache_id, std::vector<FallbackNameSpaceRecord>* records); - bool InsertFallbackNameSpace(const FallbackNameSpaceRecord* record); - bool InsertFallbackNameSpaceRecords( - const std::vector<FallbackNameSpaceRecord>& records); - bool DeleteFallbackNameSpacesForCache(int64 cache_id); - - bool FindOnlineWhiteListForCache( - int64 cache_id, std::vector<OnlineWhiteListRecord>* records); - bool InsertOnlineWhiteList(const OnlineWhiteListRecord* record); - bool InsertOnlineWhiteListRecords( - const std::vector<OnlineWhiteListRecord>& records); - bool DeleteOnlineWhiteListForCache(int64 cache_id); - - // So our callers can wrap operations in transactions. - sql::Connection* db_connection() { - LazyOpen(true); - return db_.get(); - } - - private: - bool PrepareUniqueStatement(const char* sql, sql::Statement* statement); - bool PrepareCachedStatement( - const sql::StatementID& id, const char* sql, sql::Statement* statement); - - // Record retrieval helpers - void ReadGroupRecord(const sql::Statement& statement, GroupRecord* record); - void ReadCacheRecord(const sql::Statement& statement, CacheRecord* record); - void ReadEntryRecord(const sql::Statement& statement, EntryRecord* record); - void ReadFallbackNameSpaceRecord( - const sql::Statement& statement, FallbackNameSpaceRecord* record); - void ReadOnlineWhiteListRecord( - const sql::Statement& statement, OnlineWhiteListRecord* record); - - // Database creation - bool LazyOpen(bool create_if_needed); - bool EnsureDatabaseVersion(); - bool CreateSchema(); - bool UpgradeSchema(); - - // Deletes the existing database file and the entire directory containing - // the database file including the disk cache in which response headers - // and bodies are stored, and then creates a new database file. - bool DeleteExistingAndCreateNewDatabase(); - - FilePath db_file_path_; - scoped_ptr<sql::Connection> db_; - scoped_ptr<sql::MetaTable> meta_table_; - bool has_open_error_; - bool is_recreating_; - - FRIEND_TEST(AppCacheDatabaseTest, CacheRecords); - FRIEND_TEST(AppCacheDatabaseTest, EntryRecords); - FRIEND_TEST(AppCacheDatabaseTest, FallbackNameSpaceRecords); - FRIEND_TEST(AppCacheDatabaseTest, GroupRecords); - FRIEND_TEST(AppCacheDatabaseTest, LazyOpen); - FRIEND_TEST(AppCacheDatabaseTest, OnlineWhiteListRecords); - FRIEND_TEST(AppCacheDatabaseTest, ReCreate); - DISALLOW_COPY_AND_ASSIGN(AppCacheDatabase); -}; - -} // namespace appcache - -#endif // WEBKIT_APPCACHE_APPCACHE_DATABASE_H_ diff --git a/webkit/appcache/appcache_database_unittest.cc b/webkit/appcache/appcache_database_unittest.cc deleted file mode 100644 index 62ff4ca..0000000 --- a/webkit/appcache/appcache_database_unittest.cc +++ /dev/null @@ -1,439 +0,0 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "testing/gtest/include/gtest/gtest.h" - -#include "app/sql/connection.h" -#include "base/file_util.h" -#include "base/scoped_temp_dir.h" -#include "webkit/appcache/appcache_database.h" -#include "webkit/appcache/appcache_entry.h" - -namespace { - -const base::TimeTicks kZeroTimeTicks; - -class TestErrorDelegate : public sql::ErrorDelegate { - public: - virtual ~TestErrorDelegate() { } - virtual int OnError( - int error, sql::Connection* connection, sql::Statement* stmt) { - return error; - } -}; - -} // namespace - -namespace appcache { - -class AppCacheDatabaseTest {}; - -TEST(AppCacheDatabaseTest, LazyOpen) { - // Use an empty file path to use an in-memory sqlite database. - const FilePath kEmptyPath; - AppCacheDatabase db(kEmptyPath); - - EXPECT_FALSE(db.LazyOpen(false)); - EXPECT_TRUE(db.LazyOpen(true)); - - int64 group_id, cache_id, response_id; - group_id = cache_id = response_id = 0; - EXPECT_TRUE(db.FindLastStorageIds(&group_id, &cache_id, &response_id)); - EXPECT_EQ(0, group_id); - EXPECT_EQ(0, cache_id); - EXPECT_EQ(0, response_id); - - std::set<GURL> origins; - EXPECT_TRUE(db.FindOriginsWithGroups(&origins)); - EXPECT_TRUE(origins.empty()); -} - -TEST(AppCacheDatabaseTest, ReCreate) { - // Real files on disk for this test. - ScopedTempDir temp_dir; - EXPECT_TRUE(temp_dir.CreateUniqueTempDir()); - const FilePath kDbFile = temp_dir.path().AppendASCII("appcache.db"); - const FilePath kNestedDir = temp_dir.path().AppendASCII("nested"); - const FilePath kOtherFile = kNestedDir.AppendASCII("other_file"); - EXPECT_TRUE(file_util::CreateDirectory(kNestedDir)); - EXPECT_EQ(3, file_util::WriteFile(kOtherFile, "foo", 3)); - - AppCacheDatabase db(kDbFile); - EXPECT_FALSE(db.LazyOpen(false)); - EXPECT_TRUE(db.LazyOpen(true)); - - EXPECT_TRUE(file_util::PathExists(kDbFile)); - EXPECT_TRUE(file_util::DirectoryExists(kNestedDir)); - EXPECT_TRUE(file_util::PathExists(kOtherFile)); - - EXPECT_TRUE(db.DeleteExistingAndCreateNewDatabase()); - - EXPECT_TRUE(file_util::PathExists(kDbFile)); - EXPECT_FALSE(file_util::DirectoryExists(kNestedDir)); - EXPECT_FALSE(file_util::PathExists(kOtherFile)); -} - -TEST(AppCacheDatabaseTest, EntryRecords) { - const FilePath kEmptyPath; - AppCacheDatabase db(kEmptyPath); - EXPECT_TRUE(db.LazyOpen(true)); - - // Set an error delegate that will make all operations return false on error. - scoped_refptr<TestErrorDelegate> error_delegate(new TestErrorDelegate); - db.db_->set_error_delegate(error_delegate); - - AppCacheDatabase::EntryRecord entry; - - entry.cache_id = 1; - entry.url = GURL("http://blah/1"); - entry.flags = AppCacheEntry::MASTER; - entry.response_id = 1; - EXPECT_TRUE(db.InsertEntry(&entry)); - EXPECT_FALSE(db.InsertEntry(&entry)); - - entry.cache_id = 2; - entry.url = GURL("http://blah/2"); - entry.flags = AppCacheEntry::EXPLICIT; - entry.response_id = 2; - EXPECT_TRUE(db.InsertEntry(&entry)); - - entry.cache_id = 2; - entry.url = GURL("http://blah/3"); - entry.flags = AppCacheEntry::MANIFEST; - entry.response_id = 3; - EXPECT_TRUE(db.InsertEntry(&entry)); - - std::vector<AppCacheDatabase::EntryRecord> found; - - EXPECT_TRUE(db.FindEntriesForCache(1, &found)); - EXPECT_EQ(1U, found.size()); - EXPECT_EQ(1, found[0].cache_id); - EXPECT_EQ(GURL("http://blah/1"), found[0].url); - EXPECT_EQ(AppCacheEntry::MASTER, found[0].flags); - EXPECT_EQ(1, found[0].response_id); - found.clear(); - - EXPECT_TRUE(db.AddEntryFlags(GURL("http://blah/1"), 1, - AppCacheEntry::FOREIGN)); - EXPECT_TRUE(db.FindEntriesForCache(1, &found)); - EXPECT_EQ(1U, found.size()); - EXPECT_EQ(AppCacheEntry::MASTER | AppCacheEntry::FOREIGN, found[0].flags); - found.clear(); - - EXPECT_TRUE(db.FindEntriesForCache(2, &found)); - EXPECT_EQ(2U, found.size()); - EXPECT_EQ(2, found[0].cache_id); - EXPECT_EQ(GURL("http://blah/2"), found[0].url); - EXPECT_EQ(AppCacheEntry::EXPLICIT, found[0].flags); - EXPECT_EQ(2, found[0].response_id); - EXPECT_EQ(2, found[1].cache_id); - EXPECT_EQ(GURL("http://blah/3"), found[1].url); - EXPECT_EQ(AppCacheEntry::MANIFEST, found[1].flags); - EXPECT_EQ(3, found[1].response_id); - found.clear(); - - EXPECT_TRUE(db.DeleteEntriesForCache(2)); - EXPECT_TRUE(db.FindEntriesForCache(2, &found)); - EXPECT_TRUE(found.empty()); - found.clear(); - - EXPECT_TRUE(db.DeleteEntriesForCache(1)); - EXPECT_FALSE(db.AddEntryFlags(GURL("http://blah/1"), 1, - AppCacheEntry::FOREIGN)); -} - -TEST(AppCacheDatabaseTest, CacheRecords) { - const FilePath kEmptyPath; - AppCacheDatabase db(kEmptyPath); - EXPECT_TRUE(db.LazyOpen(true)); - - scoped_refptr<TestErrorDelegate> error_delegate(new TestErrorDelegate); - db.db_->set_error_delegate(error_delegate); - - const AppCacheDatabase::CacheRecord kZeroRecord = {0}; - AppCacheDatabase::CacheRecord record = kZeroRecord; - EXPECT_FALSE(db.FindCache(1, &record)); - - record.cache_id = 1; - record.group_id = 1; - record.online_wildcard = true; - record.update_time = kZeroTimeTicks; - EXPECT_TRUE(db.InsertCache(&record)); - EXPECT_FALSE(db.InsertCache(&record)); - - record = kZeroRecord; - EXPECT_TRUE(db.FindCache(1, &record)); - EXPECT_EQ(1, record.cache_id); - EXPECT_EQ(1, record.group_id); - EXPECT_TRUE(record.online_wildcard); - EXPECT_TRUE(kZeroTimeTicks == record.update_time); - - record = kZeroRecord; - EXPECT_TRUE(db.FindCacheForGroup(1, &record)); - EXPECT_EQ(1, record.cache_id); - EXPECT_EQ(1, record.group_id); - EXPECT_TRUE(record.online_wildcard); - EXPECT_TRUE(kZeroTimeTicks == record.update_time); - - EXPECT_TRUE(db.DeleteCache(1)); - EXPECT_FALSE(db.FindCache(1, &record)); - EXPECT_FALSE(db.FindCacheForGroup(1, &record)); - - EXPECT_TRUE(db.DeleteCache(1)); -} - -TEST(AppCacheDatabaseTest, GroupRecords) { - const FilePath kEmptyPath; - AppCacheDatabase db(kEmptyPath); - EXPECT_TRUE(db.LazyOpen(true)); - - scoped_refptr<TestErrorDelegate> error_delegate(new TestErrorDelegate); - db.db_->set_error_delegate(error_delegate); - - const GURL kManifestUrl("http://blah/manifest"); - const GURL kOrigin(kManifestUrl.GetOrigin()); - - const AppCacheDatabase::GroupRecord kZeroRecord = {0, GURL(), GURL()}; - AppCacheDatabase::GroupRecord record = kZeroRecord; - std::vector<AppCacheDatabase::GroupRecord> records; - - // Behavior with an empty table - EXPECT_FALSE(db.FindGroup(1, &record)); - EXPECT_FALSE(db.FindGroupForManifestUrl(kManifestUrl, &record)); - EXPECT_TRUE(db.DeleteGroup(1)); - EXPECT_TRUE(db.FindGroupsForOrigin(kOrigin, &records)); - EXPECT_TRUE(records.empty()); - EXPECT_FALSE(db.FindGroupForCache(1, &record)); - - record.group_id = 1; - record.manifest_url = kManifestUrl; - record.origin = kOrigin; - EXPECT_TRUE(db.InsertGroup(&record)); - EXPECT_FALSE(db.InsertGroup(&record)); - - record.group_id = 2; - EXPECT_FALSE(db.InsertGroup(&record)); - - record = kZeroRecord; - EXPECT_TRUE(db.FindGroup(1, &record)); - EXPECT_EQ(1, record.group_id); - EXPECT_EQ(kManifestUrl, record.manifest_url); - EXPECT_EQ(kOrigin, record.origin); - - record = kZeroRecord; - EXPECT_TRUE(db.FindGroupForManifestUrl(kManifestUrl, &record)); - EXPECT_EQ(1, record.group_id); - EXPECT_EQ(kManifestUrl, record.manifest_url); - EXPECT_EQ(kOrigin, record.origin); - - record.group_id = 2; - record.manifest_url = kOrigin; - record.origin = kOrigin; - EXPECT_TRUE(db.InsertGroup(&record)); - - record = kZeroRecord; - EXPECT_TRUE(db.FindGroupForManifestUrl(kOrigin, &record)); - EXPECT_EQ(2, record.group_id); - EXPECT_EQ(kOrigin, record.manifest_url); - EXPECT_EQ(kOrigin, record.origin); - - EXPECT_TRUE(db.FindGroupsForOrigin(kOrigin, &records)); - EXPECT_EQ(2U, records.size()); - EXPECT_EQ(1, records[0].group_id); - EXPECT_EQ(kManifestUrl, records[0].manifest_url); - EXPECT_EQ(kOrigin, records[0].origin); - EXPECT_EQ(2, records[1].group_id); - EXPECT_EQ(kOrigin, records[1].manifest_url); - EXPECT_EQ(kOrigin, records[1].origin); - - EXPECT_TRUE(db.DeleteGroup(1)); - - records.clear(); - EXPECT_TRUE(db.FindGroupsForOrigin(kOrigin, &records)); - EXPECT_EQ(1U, records.size()); - EXPECT_EQ(2, records[0].group_id); - EXPECT_EQ(kOrigin, records[0].manifest_url); - EXPECT_EQ(kOrigin, records[0].origin); - - std::set<GURL> origins; - EXPECT_TRUE(db.FindOriginsWithGroups(&origins)); - EXPECT_EQ(1U, origins.size()); - EXPECT_EQ(kOrigin, *(origins.begin())); - - const GURL kManifest2("http://blah2/manifest"); - const GURL kOrigin2(kManifest2.GetOrigin()); - record.group_id = 1; - record.manifest_url = kManifest2; - record.origin = kOrigin2; - EXPECT_TRUE(db.InsertGroup(&record)); - - origins.clear(); - EXPECT_TRUE(db.FindOriginsWithGroups(&origins)); - EXPECT_EQ(2U, origins.size()); - EXPECT_TRUE(origins.end() != origins.find(kOrigin)); - EXPECT_TRUE(origins.end() != origins.find(kOrigin2)); - - AppCacheDatabase::CacheRecord cache_record; - cache_record.cache_id = 1; - cache_record.group_id = 1; - cache_record.online_wildcard = true; - cache_record.update_time = kZeroTimeTicks; - EXPECT_TRUE(db.InsertCache(&cache_record)); - - record = kZeroRecord; - EXPECT_TRUE(db.FindGroupForCache(1, &record)); - EXPECT_EQ(1, record.group_id); - EXPECT_EQ(kManifest2, record.manifest_url); - EXPECT_EQ(kOrigin2, record.origin); -} - -TEST(AppCacheDatabaseTest, FallbackNameSpaceRecords) { - const FilePath kEmptyPath; - AppCacheDatabase db(kEmptyPath); - EXPECT_TRUE(db.LazyOpen(true)); - - scoped_refptr<TestErrorDelegate> error_delegate(new TestErrorDelegate); - db.db_->set_error_delegate(error_delegate); - - const GURL kFooNameSpace1("http://foo/namespace1"); - const GURL kFooNameSpace2("http://foo/namespace2"); - const GURL kFooFallbackEntry("http://foo/entry"); - const GURL kFooOrigin(kFooNameSpace1.GetOrigin()); - const GURL kBarNameSpace1("http://bar/namespace1"); - const GURL kBarNameSpace2("http://bar/namespace2"); - const GURL kBarFallbackEntry("http://bar/entry"); - const GURL kBarOrigin(kBarNameSpace1.GetOrigin()); - - const AppCacheDatabase::FallbackNameSpaceRecord kZeroRecord = - { 0, GURL(), GURL(), GURL() }; - AppCacheDatabase::FallbackNameSpaceRecord record = kZeroRecord; - std::vector<AppCacheDatabase::FallbackNameSpaceRecord> records; - - // Behavior with an empty table - EXPECT_TRUE(db.FindFallbackNameSpacesForCache(1, &records)); - EXPECT_TRUE(records.empty()); - EXPECT_TRUE(db.FindFallbackNameSpacesForOrigin(kFooOrigin, &records)); - EXPECT_TRUE(records.empty()); - EXPECT_TRUE(db.DeleteFallbackNameSpacesForCache(1)); - - // Two records for two differenent caches in the Foo origin. - record.cache_id = 1; - record.origin = kFooOrigin; - record.namespace_url = kFooNameSpace1; - record.fallback_entry_url = kFooFallbackEntry; - EXPECT_TRUE(db.InsertFallbackNameSpace(&record)); - EXPECT_FALSE(db.InsertFallbackNameSpace(&record)); - - record.cache_id = 2; - record.origin = kFooOrigin; - record.namespace_url = kFooNameSpace2; - record.fallback_entry_url = kFooFallbackEntry; - EXPECT_TRUE(db.InsertFallbackNameSpace(&record)); - - records.clear(); - EXPECT_TRUE(db.FindFallbackNameSpacesForCache(1, &records)); - EXPECT_EQ(1U, records.size()); - EXPECT_EQ(1, records[0].cache_id); - EXPECT_EQ(kFooOrigin, records[0].origin); - EXPECT_EQ(kFooNameSpace1, records[0].namespace_url); - EXPECT_EQ(kFooFallbackEntry, records[0].fallback_entry_url); - - records.clear(); - EXPECT_TRUE(db.FindFallbackNameSpacesForCache(2, &records)); - EXPECT_EQ(1U, records.size()); - EXPECT_EQ(2, records[0].cache_id); - EXPECT_EQ(kFooOrigin, records[0].origin); - EXPECT_EQ(kFooNameSpace2, records[0].namespace_url); - EXPECT_EQ(kFooFallbackEntry, records[0].fallback_entry_url); - - records.clear(); - EXPECT_TRUE(db.FindFallbackNameSpacesForOrigin(kFooOrigin, &records)); - EXPECT_EQ(2U, records.size()); - EXPECT_EQ(1, records[0].cache_id); - EXPECT_EQ(kFooOrigin, records[0].origin); - EXPECT_EQ(kFooNameSpace1, records[0].namespace_url); - EXPECT_EQ(kFooFallbackEntry, records[0].fallback_entry_url); - EXPECT_EQ(2, records[1].cache_id); - EXPECT_EQ(kFooOrigin, records[1].origin); - EXPECT_EQ(kFooNameSpace2, records[1].namespace_url); - EXPECT_EQ(kFooFallbackEntry, records[1].fallback_entry_url); - - EXPECT_TRUE(db.DeleteFallbackNameSpacesForCache(1)); - records.clear(); - EXPECT_TRUE(db.FindFallbackNameSpacesForOrigin(kFooOrigin, &records)); - EXPECT_EQ(1U, records.size()); - EXPECT_EQ(2, records[0].cache_id); - EXPECT_EQ(kFooOrigin, records[0].origin); - EXPECT_EQ(kFooNameSpace2, records[0].namespace_url); - EXPECT_EQ(kFooFallbackEntry, records[0].fallback_entry_url); - - // Two more records for the same cache in the Bar origin. - record.cache_id = 3; - record.origin = kBarOrigin; - record.namespace_url = kBarNameSpace1; - record.fallback_entry_url = kBarFallbackEntry; - EXPECT_TRUE(db.InsertFallbackNameSpace(&record)); - - record.cache_id = 3; - record.origin = kBarOrigin; - record.namespace_url = kBarNameSpace2; - record.fallback_entry_url = kBarFallbackEntry; - EXPECT_TRUE(db.InsertFallbackNameSpace(&record)); - - records.clear(); - EXPECT_TRUE(db.FindFallbackNameSpacesForCache(3, &records)); - EXPECT_EQ(2U, records.size()); - records.clear(); - EXPECT_TRUE(db.FindFallbackNameSpacesForOrigin(kBarOrigin, &records)); - EXPECT_EQ(2U, records.size()); -} - -TEST(AppCacheDatabaseTest, OnlineWhiteListRecords) { - const FilePath kEmptyPath; - AppCacheDatabase db(kEmptyPath); - EXPECT_TRUE(db.LazyOpen(true)); - - scoped_refptr<TestErrorDelegate> error_delegate(new TestErrorDelegate); - db.db_->set_error_delegate(error_delegate); - - const GURL kFooNameSpace1("http://foo/namespace1"); - const GURL kFooNameSpace2("http://foo/namespace2"); - const GURL kBarNameSpace1("http://bar/namespace1"); - - const AppCacheDatabase::OnlineWhiteListRecord kZeroRecord = { 0, GURL() }; - AppCacheDatabase::OnlineWhiteListRecord record = kZeroRecord; - std::vector<AppCacheDatabase::OnlineWhiteListRecord> records; - - // Behavior with an empty table - EXPECT_TRUE(db.FindOnlineWhiteListForCache(1, &records)); - EXPECT_TRUE(records.empty()); - EXPECT_TRUE(db.DeleteOnlineWhiteListForCache(1)); - - record.cache_id = 1; - record.namespace_url = kFooNameSpace1; - EXPECT_TRUE(db.InsertOnlineWhiteList(&record)); - record.namespace_url = kFooNameSpace2; - EXPECT_TRUE(db.InsertOnlineWhiteList(&record)); - records.clear(); - EXPECT_TRUE(db.FindOnlineWhiteListForCache(1, &records)); - EXPECT_EQ(2U, records.size()); - EXPECT_EQ(1, records[0].cache_id); - EXPECT_EQ(kFooNameSpace1, records[0].namespace_url); - EXPECT_EQ(1, records[1].cache_id); - EXPECT_EQ(kFooNameSpace2, records[1].namespace_url); - - record.cache_id = 2; - record.namespace_url = kBarNameSpace1; - EXPECT_TRUE(db.InsertOnlineWhiteList(&record)); - records.clear(); - EXPECT_TRUE(db.FindOnlineWhiteListForCache(2, &records)); - EXPECT_EQ(1U, records.size()); - - EXPECT_TRUE(db.DeleteOnlineWhiteListForCache(1)); - records.clear(); - EXPECT_TRUE(db.FindOnlineWhiteListForCache(1, &records)); - EXPECT_TRUE(records.empty()); -} - -} // namespace appcache diff --git a/webkit/appcache/appcache_group_unittest.cc b/webkit/appcache/appcache_group_unittest.cc index 180cc3a..5986021 100644 --- a/webkit/appcache/appcache_group_unittest.cc +++ b/webkit/appcache/appcache_group_unittest.cc @@ -77,7 +77,7 @@ class AppCacheGroupTest : public testing::Test { TEST(AppCacheGroupTest, AddRemoveCache) { MockAppCacheService service; scoped_refptr<AppCacheGroup> group = - new AppCacheGroup(&service, GURL("http://foo.com"), 111); + new AppCacheGroup(&service, GURL::EmptyGURL(), 111); base::TimeTicks ticks = base::TimeTicks::Now(); @@ -146,8 +146,7 @@ TEST(AppCacheGroupTest, AddRemoveCache) { TEST(AppCacheGroupTest, CleanupUnusedGroup) { MockAppCacheService service; TestAppCacheFrontend frontend; - AppCacheGroup* group = - new AppCacheGroup(&service, GURL("http://foo.com"), 111); + AppCacheGroup* group = new AppCacheGroup(&service, GURL::EmptyGURL(), 111); AppCacheHost host1(1, &frontend, &service); AppCacheHost host2(2, &frontend, &service); diff --git a/webkit/appcache/appcache_host.cc b/webkit/appcache/appcache_host.cc index 489d062..6a62a44 100644 --- a/webkit/appcache/appcache_host.cc +++ b/webkit/appcache/appcache_host.cc @@ -300,7 +300,6 @@ void AppCacheHost::FinishCacheSelection( void AppCacheHost::ObserveGroupBeingUpdated(AppCacheGroup* group) { DCHECK(!group_being_updated_); group_being_updated_ = group; - newest_cache_of_group_being_updated_ = group->newest_complete_cache(); group->AddUpdateObserver(this); } @@ -312,7 +311,6 @@ void AppCacheHost::OnUpdateComplete(AppCacheGroup* group) { SetSwappableCache(group); group_being_updated_ = NULL; - newest_cache_of_group_being_updated_ = NULL; } void AppCacheHost::SetSwappableCache(AppCacheGroup* group) { diff --git a/webkit/appcache/appcache_host.h b/webkit/appcache/appcache_host.h index 3029cd3..13acdb0 100644 --- a/webkit/appcache/appcache_host.h +++ b/webkit/appcache/appcache_host.h @@ -135,11 +135,6 @@ class AppCacheHost : public AppCacheStorage::Delegate, // Keep a reference to the group being updated until the update completes. scoped_refptr<AppCacheGroup> group_being_updated_; - // Similarly, keep a reference to the newest cache of the group until the - // update completes. When adding a new master entry to a cache that is not - // in use in any other host, this reference keeps the cache in memory. - scoped_refptr<AppCache> newest_cache_of_group_being_updated_; - // Keep a reference to the cache of the main resource so it survives frame // navigations. scoped_refptr<AppCache> main_resource_cache_; diff --git a/webkit/appcache/appcache_storage_impl.cc b/webkit/appcache/appcache_storage_impl.cc index 04809eb..3fb8280 100644 --- a/webkit/appcache/appcache_storage_impl.cc +++ b/webkit/appcache/appcache_storage_impl.cc @@ -4,862 +4,12 @@ #include "webkit/appcache/appcache_storage_impl.h" -#include "app/sql/connection.h" -#include "app/sql/transaction.h" -#include "base/logging.h" -#include "base/message_loop.h" -#include "base/stl_util-inl.h" -#include "base/string_util.h" -#include "webkit/appcache/appcache.h" -#include "webkit/appcache/appcache_database.h" -#include "webkit/appcache/appcache_entry.h" -#include "webkit/appcache/appcache_group.h" -#include "webkit/appcache/appcache_response.h" -#include "webkit/appcache/appcache_thread.h" - namespace appcache { -static const char kAppCacheDatabaseName[] = "Index"; -static const char kDiskCacheDirectoryName[] = "Cache"; -static const int kMaxDiskCacheSize = 10 * 1024 * 1024; - -// DatabaseTask ----------------------------------------- - -class AppCacheStorageImpl::DatabaseTask - : public base::RefCountedThreadSafe<DatabaseTask> { - public: - explicit DatabaseTask(AppCacheStorageImpl* storage) - : storage_(storage), database_(storage->database_) {} - - void AddDelegate(DelegateReference* delegate_reference) { - delegates_.push_back(delegate_reference); - } - - // Schedules a task to be Run() on the DB thread. Tasks - // are run in the order in which they are scheduled. - void Schedule(); - - // Called on the DB thread. - virtual void Run() = 0; - - // Called on the IO thread after Run() has completed. - virtual void RunCompleted() {} - - // Once scheduled a task cannot be cancelled, but the - // call to RunCompleted may be. This method should only be - // called on the IO thread. This is used by AppCacheStorageImpl - // to cancel the completion calls when AppCacheStorageImpl is - // destructed. This method may be overriden to release or delete - // additional data associated with the task that is not DB thread - // safe. If overriden, this base class method must be called from - // within the override. - virtual void CancelCompletion(); - - protected: - AppCacheStorageImpl* storage_; - AppCacheDatabase* database_; - DelegateReferenceVector delegates_; - - private: - void CallRun(); - void CallRunCompleted(); -}; - -void AppCacheStorageImpl::DatabaseTask::Schedule() { - DCHECK(storage_); - DCHECK(AppCacheThread::CurrentlyOn(AppCacheThread::io())); - storage_->scheduled_database_tasks_.push_back(this); - AppCacheThread::PostTask(AppCacheThread::db(), FROM_HERE, - NewRunnableMethod(this, &DatabaseTask::CallRun)); -} - -void AppCacheStorageImpl::DatabaseTask::CancelCompletion() { - DCHECK(AppCacheThread::CurrentlyOn(AppCacheThread::io())); - delegates_.clear(); - storage_ = NULL; -} - -void AppCacheStorageImpl::DatabaseTask::CallRun() { - DCHECK(AppCacheThread::CurrentlyOn(AppCacheThread::db())); - Run(); - AppCacheThread::PostTask(AppCacheThread::io(), FROM_HERE, - NewRunnableMethod(this, &DatabaseTask::CallRunCompleted)); -} - -void AppCacheStorageImpl::DatabaseTask::CallRunCompleted() { - if (storage_) { - DCHECK(AppCacheThread::CurrentlyOn(AppCacheThread::io())); - DCHECK(storage_->scheduled_database_tasks_.front() == this); - storage_->scheduled_database_tasks_.pop_front(); - RunCompleted(); - } -} - -// InitTask ------- - -class AppCacheStorageImpl::InitTask : public DatabaseTask { - public: - explicit InitTask(AppCacheStorageImpl* storage) - : DatabaseTask(storage), last_group_id_(0), - last_cache_id_(0), last_response_id_(0) {} - - virtual void Run(); - virtual void RunCompleted(); - - int64 last_group_id_; - int64 last_cache_id_; - int64 last_response_id_; - std::set<GURL> origins_with_groups_; -}; - -void AppCacheStorageImpl::InitTask::Run() { - database_->FindLastStorageIds( - &last_group_id_, &last_cache_id_, &last_response_id_); - database_->FindOriginsWithGroups(&origins_with_groups_); -} - -void AppCacheStorageImpl::InitTask::RunCompleted() { - storage_->last_group_id_ = last_group_id_; - storage_->last_cache_id_ = last_cache_id_; - storage_->last_response_id_ = last_response_id_; - storage_->origins_with_groups_.swap(origins_with_groups_); -} - -// CloseConnectionTask ------- - -class AppCacheStorageImpl::CloseConnectionTask : public DatabaseTask { - public: - explicit CloseConnectionTask(AppCacheStorageImpl* storage) - : DatabaseTask(storage) {} - - virtual void Run() { database_->CloseConnection(); } -}; - -// StoreOrLoadTask ------- - -class AppCacheStorageImpl::StoreOrLoadTask : public DatabaseTask { - protected: - explicit StoreOrLoadTask(AppCacheStorageImpl* storage) - : DatabaseTask(storage) {} - - bool FindRelatedCacheRecords(int64 cache_id); - void CreateCacheAndGroupFromRecords( - scoped_refptr<AppCache>* cache, scoped_refptr<AppCacheGroup>* group); - - AppCacheDatabase::GroupRecord group_record_; - AppCacheDatabase::CacheRecord cache_record_; - std::vector<AppCacheDatabase::EntryRecord> entry_records_; - std::vector<AppCacheDatabase::FallbackNameSpaceRecord> - fallback_namespace_records_; - std::vector<AppCacheDatabase::OnlineWhiteListRecord> - online_whitelist_records_; -}; - -bool AppCacheStorageImpl::StoreOrLoadTask::FindRelatedCacheRecords( - int64 cache_id) { - return database_->FindEntriesForCache(cache_id, &entry_records_) && - database_->FindFallbackNameSpacesForCache( - cache_id, &fallback_namespace_records_) && - database_->FindOnlineWhiteListForCache( - cache_id, &online_whitelist_records_); -} - -void AppCacheStorageImpl::StoreOrLoadTask::CreateCacheAndGroupFromRecords( - scoped_refptr<AppCache>* cache, scoped_refptr<AppCacheGroup>* group) { - DCHECK(storage_ && cache && group); - - (*cache) = new AppCache(storage_->service_, cache_record_.cache_id); - cache->get()->InitializeWithDatabaseRecords( - cache_record_, entry_records_, fallback_namespace_records_, - online_whitelist_records_); - cache->get()->set_complete(true); - - (*group) = storage_->working_set_.GetGroup(group_record_.manifest_url); - if (group->get()) { - DCHECK(group_record_.group_id == group->get()->group_id()); - group->get()->AddCache(cache->get()); - } else { - (*group) = new AppCacheGroup( - storage_->service_, group_record_.manifest_url, - group_record_.group_id); - group->get()->AddCache(cache->get()); - } - DCHECK(group->get()->newest_complete_cache() == cache->get()); - - // We have to update foriegn entries if MarkEntryAsForeignTasks - // are in flight. - std::vector<GURL> urls; - storage_->GetPendingForeignMarkingsForCache(cache->get()->cache_id(), &urls); - for (std::vector<GURL>::iterator iter = urls.begin(); - iter != urls.end(); ++iter) { - DCHECK(cache->get()->GetEntry(*iter)); - cache->get()->GetEntry(*iter)->add_types(AppCacheEntry::FOREIGN); - } -} - -// CacheLoadTask ------- - -class AppCacheStorageImpl::CacheLoadTask : public StoreOrLoadTask { - public: - CacheLoadTask(int64 cache_id, AppCacheStorageImpl* storage) - : StoreOrLoadTask(storage), cache_id_(cache_id), - success_(false) {} - - virtual void Run(); - virtual void RunCompleted(); - - int64 cache_id_; - bool success_; -}; - -void AppCacheStorageImpl::CacheLoadTask::Run() { - success_ = - database_->FindCache(cache_id_, &cache_record_) && - database_->FindGroup(cache_record_.group_id, &group_record_) && - FindRelatedCacheRecords(cache_id_); -} - -void AppCacheStorageImpl::CacheLoadTask::RunCompleted() { - storage_->pending_cache_loads_.erase(cache_id_); - scoped_refptr<AppCache> cache; - scoped_refptr<AppCacheGroup> group; - if (success_) { - DCHECK(cache_record_.cache_id == cache_id_); - DCHECK(!storage_->working_set_.GetCache(cache_record_.cache_id)); - CreateCacheAndGroupFromRecords(&cache, &group); - } - FOR_EACH_DELEGATE(delegates_, OnCacheLoaded(cache, cache_id_)); -} - -// GroupLoadTask ------- - -class AppCacheStorageImpl::GroupLoadTask : public StoreOrLoadTask { - public: - GroupLoadTask(GURL manifest_url, AppCacheStorageImpl* storage) - : StoreOrLoadTask(storage), manifest_url_(manifest_url), - success_(false) {} - - virtual void Run(); - virtual void RunCompleted(); - - GURL manifest_url_; - bool success_; -}; - -void AppCacheStorageImpl::GroupLoadTask::Run() { - success_ = - database_->FindGroupForManifestUrl(manifest_url_, &group_record_) && - database_->FindCacheForGroup(group_record_.group_id, &cache_record_) && - FindRelatedCacheRecords(cache_record_.cache_id); -} - -void AppCacheStorageImpl::GroupLoadTask::RunCompleted() { - storage_->pending_group_loads_.erase(manifest_url_); - scoped_refptr<AppCacheGroup> group; - scoped_refptr<AppCache> cache; - if (success_) { - DCHECK(group_record_.manifest_url == manifest_url_); - DCHECK(!storage_->working_set_.GetGroup(manifest_url_)); - DCHECK(!storage_->working_set_.GetCache(cache_record_.cache_id)); - CreateCacheAndGroupFromRecords(&cache, &group); - } else { - group = new AppCacheGroup( - storage_->service_, manifest_url_, - storage_->NewGroupId()); - } - FOR_EACH_DELEGATE(delegates_, OnGroupLoaded(group, manifest_url_)); -} - -// StoreGroupAndCacheTask ------- - -class AppCacheStorageImpl::StoreGroupAndCacheTask : public StoreOrLoadTask { - public: - StoreGroupAndCacheTask(AppCacheStorageImpl* storage, AppCacheGroup* group, - AppCache* newest_cache); - - virtual void Run(); - virtual void RunCompleted(); - virtual void CancelCompletion(); - - scoped_refptr<AppCacheGroup> group_; - scoped_refptr<AppCache> cache_; - bool success_; -}; - -AppCacheStorageImpl::StoreGroupAndCacheTask::StoreGroupAndCacheTask( - AppCacheStorageImpl* storage, AppCacheGroup* group, AppCache* newest_cache) - : StoreOrLoadTask(storage), group_(group), cache_(newest_cache), - success_(false) { - group_record_.group_id = group->group_id(); - group_record_.manifest_url = group->manifest_url(); - group_record_.origin = group_record_.manifest_url.GetOrigin(); - newest_cache->ToDatabaseRecords( - group, - &cache_record_, &entry_records_, &fallback_namespace_records_, - &online_whitelist_records_); -} - -void AppCacheStorageImpl::StoreGroupAndCacheTask::Run() { - DCHECK(!success_); - sql::Connection* connection = database_->db_connection(); - if (!connection) - return; - - sql::Transaction transaction(connection); - if (!transaction.Begin()) - return; - - AppCacheDatabase::GroupRecord existing_group; - success_ = database_->FindGroup(group_record_.group_id, &existing_group); - if (!success_) { - success_ = database_->InsertGroup(&group_record_); - } else { - DCHECK(group_record_.group_id == existing_group.group_id); - DCHECK(group_record_.manifest_url == existing_group.manifest_url); - DCHECK(group_record_.origin == existing_group.origin); - - AppCacheDatabase::CacheRecord cache; - if (database_->FindCacheForGroup(group_record_.group_id, &cache)) { - success_ = - database_->DeleteCache(cache.cache_id) && - database_->DeleteEntriesForCache(cache.cache_id) && - database_->DeleteFallbackNameSpacesForCache(cache.cache_id) && - database_->DeleteOnlineWhiteListForCache(cache.cache_id); - // TODO(michaeln): schedule to purge unused responses from the disk cache - } else { - NOTREACHED() << "A existing group without a cache is unexpected"; - } - } - - success_ = - success_ && - database_->InsertCache(&cache_record_) && - database_->InsertEntryRecords(entry_records_) && - database_->InsertFallbackNameSpaceRecords(fallback_namespace_records_)&& - database_->InsertOnlineWhiteListRecords(online_whitelist_records_) && - transaction.Commit(); -} - -void AppCacheStorageImpl::StoreGroupAndCacheTask::RunCompleted() { - if (success_) { - storage_->origins_with_groups_.insert(group_->manifest_url().GetOrigin()); - if (cache_ != group_->newest_complete_cache()) - group_->AddCache(cache_); - } - FOR_EACH_DELEGATE(delegates_, OnGroupAndNewestCacheStored(group_, success_)); - group_ = NULL; - cache_ = NULL; -} - -void AppCacheStorageImpl::StoreGroupAndCacheTask::CancelCompletion() { - // Overriden to safely drop our reference to the group and cache - // which are not thread safe refcounted. - DatabaseTask::CancelCompletion(); - group_ = NULL; - cache_ = NULL; -} - -// FindMainResponseTask ------- - -class AppCacheStorageImpl::FindMainResponseTask : public DatabaseTask { - public: - FindMainResponseTask(AppCacheStorageImpl* storage, const GURL& url, - const AppCacheWorkingSet::GroupMap* groups_in_use) - : DatabaseTask(storage), url_(url), cache_id_(kNoCacheId) { - if (groups_in_use) { - for (AppCacheWorkingSet::GroupMap::const_iterator it = - groups_in_use->begin(); - it != groups_in_use->end(); ++it) { - AppCacheGroup* group = it->second; - AppCache* cache = group->newest_complete_cache(); - if (group->is_obsolete() || !cache) - continue; - cache_ids_in_use_.insert(cache->cache_id()); - } - } - } - - virtual void Run(); - virtual void RunCompleted(); - - GURL url_; - std::set<int64> cache_ids_in_use_; - AppCacheEntry entry_; - AppCacheEntry fallback_entry_; - int64 cache_id_; - GURL manifest_url_; -}; - -namespace { - -bool SortByLength( - const AppCacheDatabase::FallbackNameSpaceRecord& lhs, - const AppCacheDatabase::FallbackNameSpaceRecord& rhs) { - return lhs.namespace_url.spec().length() > rhs.namespace_url.spec().length(); -} - -} - -void AppCacheStorageImpl::FindMainResponseTask::Run() { - // We have a bias for hits from caches that are in use. - - // TODO(michaeln): The heuristics around choosing amoungst - // multiple candidates is under specified, and just plain - // not fully understood. Refine these over time. In particular, - // * prefer candidates from newer caches - // * take into account the cache associated with the document - // that initiated the navigation - // * take into account the cache associated with the document - // currently residing in the frame being navigated - - // First look for an exact match. We don't worry about whether - // the containing cache is in-use in this loop because the - // storage class's FindResponseForMainRequest method does that - // as a pre-optimization. - std::vector<AppCacheDatabase::EntryRecord> entries; - if (database_->FindEntriesForUrl(url_, &entries) && !entries.empty()) { - std::vector<AppCacheDatabase::EntryRecord>::iterator iter; - for (iter = entries.begin(); iter < entries.end(); ++iter) { - if (iter->flags & AppCacheEntry::FOREIGN) - continue; - - AppCacheDatabase::GroupRecord group_record; - if (!database_->FindGroupForCache(iter->cache_id, &group_record)) { - NOTREACHED() << "A cache without a group is not expected."; - continue; - } - entry_ = AppCacheEntry(iter->flags, iter->response_id); - cache_id_ = iter->cache_id; - manifest_url_ = group_record.manifest_url; - return; - } - } - - // No exact matches, look at the fallback namespaces for this origin. - std::vector<AppCacheDatabase::FallbackNameSpaceRecord> fallbacks; - if (!database_->FindFallbackNameSpacesForOrigin(url_.GetOrigin(), &fallbacks) - || fallbacks.empty()) { - return; - } - - // Sort by namespace url string length, longest to shortest, - // since longer matches trump when matching a url to a namespace. - std::sort(fallbacks.begin(), fallbacks.end(), SortByLength); - - bool has_candidate = false; - GURL candidate_fallback_namespace; - std::vector<AppCacheDatabase::FallbackNameSpaceRecord>::iterator iter; - for (iter = fallbacks.begin(); iter < fallbacks.end(); ++iter) { - if (has_candidate && - (candidate_fallback_namespace.spec().length() > - iter->namespace_url.spec().length())) { - break; // Stop iterating since longer namespace prefix matches win. - } - - if (StartsWithASCII(url_.spec(), iter->namespace_url.spec(), true)) { - bool is_cache_in_use = cache_ids_in_use_.find(iter->cache_id) != - cache_ids_in_use_.end(); - - bool take_new_candidate = !has_candidate || is_cache_in_use; - - AppCacheDatabase::EntryRecord entry_record; - if (take_new_candidate && - database_->FindEntry(iter->cache_id, iter->fallback_entry_url, - &entry_record)) { - AppCacheDatabase::GroupRecord group_record; - if (!database_->FindGroupForCache(iter->cache_id, &group_record)) { - NOTREACHED() << "A cache without a group is not expected."; - continue; - } - cache_id_ = iter->cache_id; - manifest_url_ = group_record.manifest_url; - fallback_entry_ = AppCacheEntry( - entry_record.flags, entry_record.response_id); - if (is_cache_in_use) - break; // Stop iterating since we favor hits from in-use caches. - candidate_fallback_namespace = iter->namespace_url; - has_candidate = true; - } - } - } -} - -void AppCacheStorageImpl::FindMainResponseTask::RunCompleted() { - FOR_EACH_DELEGATE(delegates_, - OnMainResponseFound(url_, entry_, fallback_entry_, - cache_id_, manifest_url_)); -} - -// MarkEntryAsForeignTask ------- - -class AppCacheStorageImpl::MarkEntryAsForeignTask : public DatabaseTask { - public: - MarkEntryAsForeignTask( - AppCacheStorageImpl* storage, const GURL& url, int64 cache_id) - : DatabaseTask(storage), cache_id_(cache_id), entry_url_(url) {} - - virtual void Run(); - virtual void RunCompleted(); - - int64 cache_id_; - GURL entry_url_; -}; - -void AppCacheStorageImpl::MarkEntryAsForeignTask::Run() { - database_->AddEntryFlags(entry_url_, cache_id_, AppCacheEntry::FOREIGN); -} - -void AppCacheStorageImpl::MarkEntryAsForeignTask::RunCompleted() { - DCHECK(storage_->pending_foreign_markings_.front().first == entry_url_ && - storage_->pending_foreign_markings_.front().second == cache_id_); - storage_->pending_foreign_markings_.pop_front(); -} - -// MakeGroupObsoleteTask ------- - -class AppCacheStorageImpl::MakeGroupObsoleteTask : public DatabaseTask { - public: - MakeGroupObsoleteTask(AppCacheStorageImpl* storage, AppCacheGroup* group); - - virtual void Run(); - virtual void RunCompleted(); - virtual void CancelCompletion(); - - scoped_refptr<AppCacheGroup> group_; - int64 group_id_; - bool success_; - std::set<GURL> origins_with_groups_; -}; - -AppCacheStorageImpl::MakeGroupObsoleteTask::MakeGroupObsoleteTask( - AppCacheStorageImpl* storage, AppCacheGroup* group) - : DatabaseTask(storage), group_(group), group_id_(group->group_id()), - success_(false) { -} - -void AppCacheStorageImpl::MakeGroupObsoleteTask::Run() { - DCHECK(!success_); - sql::Connection* connection = database_->db_connection(); - if (!connection) - return; - - sql::Transaction transaction(connection); - if (!transaction.Begin()) - return; - - AppCacheDatabase::GroupRecord group_record; - if (!database_->FindGroup(group_id_, &group_record)) { - // This group doesn't exists in the database, nothing todo here. - success_ = true; - return; - } - - AppCacheDatabase::CacheRecord cache_record; - if (database_->FindCacheForGroup(group_id_, &cache_record)) { - success_ = - database_->DeleteGroup(group_id_) && - database_->DeleteCache(cache_record.cache_id) && - database_->DeleteEntriesForCache(cache_record.cache_id) && - database_->DeleteFallbackNameSpacesForCache(cache_record.cache_id) && - database_->DeleteOnlineWhiteListForCache(cache_record.cache_id); - } else { - NOTREACHED() << "A existing group without a cache is unexpected"; - success_ = database_->DeleteGroup(group_id_); - } - - success_ = success_ && - database_->FindOriginsWithGroups(&origins_with_groups_) && - transaction.Commit(); - - // TODO(michaeln): schedule to purge unused responses from the disk cache -} - -void AppCacheStorageImpl::MakeGroupObsoleteTask::RunCompleted() { - if (success_) { - storage_->origins_with_groups_.swap(origins_with_groups_); - group_->set_obsolete(true); - } - FOR_EACH_DELEGATE(delegates_, OnGroupMadeObsolete(group_, success_)); - group_ = NULL; -} - -void AppCacheStorageImpl::MakeGroupObsoleteTask::CancelCompletion() { - // Overriden to safely drop our reference to the group - // which is not thread safe refcounted. - DatabaseTask::CancelCompletion(); - group_ = NULL; -} - - -// AppCacheStorageImpl --------------------------------------------------- - -AppCacheStorageImpl::AppCacheStorageImpl(AppCacheService* service) - : AppCacheStorage(service), is_incognito_(false), - ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { -} - -AppCacheStorageImpl::~AppCacheStorageImpl() { - STLDeleteElements(&pending_simple_tasks_); - - std::for_each(scheduled_database_tasks_.begin(), - scheduled_database_tasks_.end(), - std::mem_fun(&DatabaseTask::CancelCompletion)); - - if (database_) - AppCacheThread::DeleteSoon(AppCacheThread::db(), FROM_HERE, database_); -} - void AppCacheStorageImpl::Initialize(const FilePath& cache_directory) { - // TODO(michaeln): until purging of responses is addressed in some way, - // always use incognito mode which doesn't put anything to disk. - // Uncomment the following line when responses are dealt with. - // cache_directory_ = cache_directory; - is_incognito_ = cache_directory_.empty(); - - FilePath db_file_path; - if (!is_incognito_) - db_file_path = cache_directory.AppendASCII(kAppCacheDatabaseName); - database_ = new AppCacheDatabase(db_file_path); - - scoped_refptr<InitTask> task = new InitTask(this); - task->Schedule(); -} - -void AppCacheStorageImpl::LoadCache(int64 id, Delegate* delegate) { - DCHECK(delegate); - AppCache* cache = working_set_.GetCache(id); - if (cache) { - delegate->OnCacheLoaded(cache, id); - return; - } - scoped_refptr<CacheLoadTask> task = GetPendingCacheLoadTask(id); - if (task) { - task->AddDelegate(GetOrCreateDelegateReference(delegate)); - return; - } - task = new CacheLoadTask(id, this); - task->AddDelegate(GetOrCreateDelegateReference(delegate)); - task->Schedule(); - pending_cache_loads_[id] = task; -} - -void AppCacheStorageImpl::LoadOrCreateGroup( - const GURL& manifest_url, Delegate* delegate) { - DCHECK(delegate); - AppCacheGroup* group = working_set_.GetGroup(manifest_url); - if (group) { - delegate->OnGroupLoaded(group, manifest_url); - return; - } - - scoped_refptr<GroupLoadTask> task = GetPendingGroupLoadTask(manifest_url); - if (task) { - task->AddDelegate(GetOrCreateDelegateReference(delegate)); - return; - } - - if (origins_with_groups_.find(manifest_url.GetOrigin()) == - origins_with_groups_.end()) { - // No need to query the database, return NULL immediately. - scoped_refptr<AppCacheGroup> group = new AppCacheGroup( - service_, manifest_url, NewGroupId()); - delegate->OnGroupLoaded(group, manifest_url); - return; - } - - task = new GroupLoadTask(manifest_url, this); - task->AddDelegate(GetOrCreateDelegateReference(delegate)); - task->Schedule(); - pending_group_loads_[manifest_url] = task.get(); -} - -void AppCacheStorageImpl::StoreGroupAndNewestCache( - AppCacheGroup* group, AppCache* newest_cache, Delegate* delegate) { - // TODO(michaeln): distinguish between a simple update of an existing - // cache that just adds new master entry(s), and the insertion of a - // whole new cache. The StoreGroupAndCacheTask as written will handle - // the simple update case in a very heavy weight way (delete all and - // the reinsert all over again). - DCHECK(group && delegate); - DCHECK(newest_cache && newest_cache->is_complete()); - scoped_refptr<StoreGroupAndCacheTask> task = - new StoreGroupAndCacheTask(this, group, newest_cache); - task->AddDelegate(GetOrCreateDelegateReference(delegate)); - task->Schedule(); -} - -void AppCacheStorageImpl::FindResponseForMainRequest( - const GURL& url, Delegate* delegate) { - DCHECK(delegate); - - const GURL* url_ptr = &url; - GURL url_no_ref; - if (url.has_ref()) { - GURL::Replacements replacements; - replacements.ClearRef(); - url_no_ref = url.ReplaceComponents(replacements); - url_ptr = &url_no_ref; - } - - // First look in our working set for a direct hit without having to query - // the database. - const AppCacheWorkingSet::GroupMap* groups_in_use = - working_set()->GetGroupsInOrigin(url_ptr->GetOrigin()); - if (groups_in_use) { - for (AppCacheWorkingSet::GroupMap::const_iterator it = - groups_in_use->begin(); - it != groups_in_use->end(); ++it) { - AppCacheGroup* group = it->second; - AppCache* cache = group->newest_complete_cache(); - if (group->is_obsolete() || !cache) - continue; - - AppCacheEntry* entry = cache->GetEntry(*url_ptr); - if (entry && !entry->IsForeign()) { - ScheduleSimpleTask(method_factory_.NewRunnableMethod( - &AppCacheStorageImpl::DeliverShortCircuitedFindMainResponse, - url, *entry, make_scoped_refptr(group), make_scoped_refptr(cache), - make_scoped_refptr(GetOrCreateDelegateReference(delegate)))); - return; - } - } - } - - if (origins_with_groups_.find(url.GetOrigin()) == - origins_with_groups_.end()) { - // No need to query the database, return async'ly but without going thru - // the DB thread. - scoped_refptr<AppCacheGroup> no_group; - scoped_refptr<AppCache> no_cache; - ScheduleSimpleTask(method_factory_.NewRunnableMethod( - &AppCacheStorageImpl::DeliverShortCircuitedFindMainResponse, - url, AppCacheEntry(), no_group, no_cache, - make_scoped_refptr(GetOrCreateDelegateReference(delegate)))); - return; - } - - // We have to query the database, schedule a database task to do so. - scoped_refptr<FindMainResponseTask> task = - new FindMainResponseTask(this, *url_ptr, groups_in_use); - task->AddDelegate(GetOrCreateDelegateReference(delegate)); - task->Schedule(); -} - -void AppCacheStorageImpl::DeliverShortCircuitedFindMainResponse( - const GURL& url, AppCacheEntry found_entry, - scoped_refptr<AppCacheGroup> group, scoped_refptr<AppCache> cache, - scoped_refptr<DelegateReference> delegate_ref) { - if (delegate_ref->delegate) { - delegate_ref->delegate->OnMainResponseFound( - url, found_entry, AppCacheEntry(), - cache.get() ? cache->cache_id() : kNoCacheId, - group.get() ? group->manifest_url() : GURL::EmptyGURL()); - } -} - -void AppCacheStorageImpl::FindResponseForSubRequest( - AppCache* cache, const GURL& url, - AppCacheEntry* found_entry, AppCacheEntry* found_fallback_entry, - bool* found_network_namespace) { - DCHECK(cache && cache->is_complete()); - GURL fallback_namespace_not_used; - cache->FindResponseForRequest( - url, found_entry, found_fallback_entry, - &fallback_namespace_not_used, found_network_namespace); -} - -void AppCacheStorageImpl::MarkEntryAsForeign( - const GURL& entry_url, int64 cache_id) { - AppCache* cache = working_set_.GetCache(cache_id); - if (cache) { - AppCacheEntry* entry = cache->GetEntry(entry_url); - DCHECK(entry); - if (entry) - entry->add_types(AppCacheEntry::FOREIGN); - } - scoped_refptr<MarkEntryAsForeignTask> task = - new MarkEntryAsForeignTask(this, entry_url, cache_id); - task->Schedule(); - pending_foreign_markings_.push_back(std::make_pair(entry_url, cache_id)); -} - -void AppCacheStorageImpl::MakeGroupObsolete( - AppCacheGroup* group, Delegate* delegate) { - DCHECK(group && delegate); - scoped_refptr<MakeGroupObsoleteTask> task = - new MakeGroupObsoleteTask(this, group); - task->AddDelegate(GetOrCreateDelegateReference(delegate)); - task->Schedule(); -} - -AppCacheResponseReader* AppCacheStorageImpl::CreateResponseReader( - const GURL& manifest_url, int64 response_id) { - return new AppCacheResponseReader(response_id, disk_cache()); -} - -AppCacheResponseWriter* AppCacheStorageImpl::CreateResponseWriter( - const GURL& manifest_url) { - return new AppCacheResponseWriter(NewResponseId(), disk_cache()); -} - -void AppCacheStorageImpl::DoomResponses( - const GURL& manifest_url, const std::vector<int64>& response_ids) { - // TODO(michaeln): do something here when deleting responses -} - -AppCacheStorageImpl::CacheLoadTask* -AppCacheStorageImpl::GetPendingCacheLoadTask(int64 cache_id) { - PendingCacheLoads::iterator found = pending_cache_loads_.find(cache_id); - if (found != pending_cache_loads_.end()) - return found->second; - return NULL; -} - -AppCacheStorageImpl::GroupLoadTask* -AppCacheStorageImpl::GetPendingGroupLoadTask(const GURL& manifest_url) { - PendingGroupLoads::iterator found = pending_group_loads_.find(manifest_url); - if (found != pending_group_loads_.end()) - return found->second; - return NULL; -} - -void AppCacheStorageImpl::GetPendingForeignMarkingsForCache( - int64 cache_id, std::vector<GURL>* urls) { - PendingForeignMarkings::iterator iter = pending_foreign_markings_.begin(); - while (iter != pending_foreign_markings_.end()) { - if (iter->second == cache_id) - urls->push_back(iter->first); - ++iter; - } -} - -void AppCacheStorageImpl::ScheduleSimpleTask(Task* task) { - pending_simple_tasks_.push_back(task); - MessageLoop::current()->PostTask(FROM_HERE, - method_factory_.NewRunnableMethod( - &AppCacheStorageImpl::RunOnePendingSimpleTask)); -} - -void AppCacheStorageImpl::RunOnePendingSimpleTask() { - DCHECK(!pending_simple_tasks_.empty()); - Task* task = pending_simple_tasks_.front(); - pending_simple_tasks_.pop_front(); - task->Run(); - delete task; -} - -disk_cache::Backend* AppCacheStorageImpl::disk_cache() { - if (!disk_cache_.get()) { - if (is_incognito_) { - disk_cache_.reset( - disk_cache::CreateInMemoryCacheBackend(kMaxDiskCacheSize)); - } else { - // TODO(michaeln): create a disk backed backend - disk_cache_.reset( - disk_cache::CreateInMemoryCacheBackend(kMaxDiskCacheSize)); - } - } - return disk_cache_.get(); + is_incognito_ = cache_directory.empty(); + cache_directory_ = cache_directory; + // TODO(michaeln): retrieve last_ids from storage } } // namespace appcache diff --git a/webkit/appcache/appcache_storage_impl.h b/webkit/appcache/appcache_storage_impl.h index 9debc1c..ef75d1e 100644 --- a/webkit/appcache/appcache_storage_impl.h +++ b/webkit/appcache/appcache_storage_impl.h @@ -5,102 +5,22 @@ #ifndef WEBKIT_APPCACHE_APPCACHE_STORAGE_IMPL_H_ #define WEBKIT_APPCACHE_APPCACHE_STORAGE_IMPL_H_ -#include <deque> -#include <map> -#include <set> -#include <vector> - #include "base/file_path.h" -#include "net/disk_cache/disk_cache.h" -#include "webkit/appcache/appcache_database.h" -#include "webkit/appcache/appcache_storage.h" +#include "webkit/appcache/mock_appcache_storage.h" namespace appcache { -class AppCacheStorageImpl : public AppCacheStorage { +// TODO(michaeln): write me, for now we derive from 'mock' storage. +class AppCacheStorageImpl : public MockAppCacheStorage { public: - explicit AppCacheStorageImpl(AppCacheService* service); - virtual ~AppCacheStorageImpl(); + explicit AppCacheStorageImpl(AppCacheService* service) + : MockAppCacheStorage(service), is_incognito_(false) {} void Initialize(const FilePath& cache_directory); - // AppCacheStorage methods - virtual void LoadCache(int64 id, Delegate* delegate); - virtual void LoadOrCreateGroup(const GURL& manifest_url, Delegate* delegate); - virtual void StoreGroupAndNewestCache( - AppCacheGroup* group, AppCache* newest_cache, Delegate* delegate); - virtual void FindResponseForMainRequest(const GURL& url, Delegate* delegate); - virtual void FindResponseForSubRequest( - AppCache* cache, const GURL& url, - AppCacheEntry* found_entry, AppCacheEntry* found_fallback_entry, - bool* found_network_namespace); - virtual void MarkEntryAsForeign(const GURL& entry_url, int64 cache_id); - virtual void MakeGroupObsolete(AppCacheGroup* group, Delegate* delegate); - virtual AppCacheResponseReader* CreateResponseReader( - const GURL& manifest_url, int64 response_id); - virtual AppCacheResponseWriter* CreateResponseWriter( - const GURL& manifest_url); - virtual void DoomResponses( - const GURL& manifest_url, const std::vector<int64>& response_ids); - private: - friend class AppCacheStorageImplTest; - - // A handful of tasks used to perform database operations on the - // background database thread. - class DatabaseTask; - class InitTask; - class CloseConnectionTask; - class StoreOrLoadTask; - class CacheLoadTask; - class GroupLoadTask; - class StoreGroupAndCacheTask; - class FindMainResponseTask; - class MarkEntryAsForeignTask; - class MakeGroupObsoleteTask; - - typedef std::deque<DatabaseTask*> DatabaseTaskQueue; - typedef std::map<int64, CacheLoadTask*> PendingCacheLoads; - typedef std::map<GURL, GroupLoadTask*> PendingGroupLoads; - typedef std::deque<std::pair<GURL, int64> > PendingForeignMarkings; - - CacheLoadTask* GetPendingCacheLoadTask(int64 cache_id); - GroupLoadTask* GetPendingGroupLoadTask(const GURL& manifest_url); - void GetPendingForeignMarkingsForCache( - int64 cache_id, std::vector<GURL>* urls); - - void ScheduleSimpleTask(Task* task); - void RunOnePendingSimpleTask(); - - // Sometimes we can respond without having to query the database. - void DeliverShortCircuitedFindMainResponse( - const GURL& url, AppCacheEntry found_entry, - scoped_refptr<AppCacheGroup> group, scoped_refptr<AppCache> newest_cache, - scoped_refptr<DelegateReference> delegate_ref); - - disk_cache::Backend* disk_cache(); - - // The directory in which we place files in the file system. - FilePath cache_directory_; bool is_incognito_; - - // Structures to keep track of DatabaseTasks that are in-flight. - DatabaseTaskQueue scheduled_database_tasks_; - PendingCacheLoads pending_cache_loads_; - PendingGroupLoads pending_group_loads_; - PendingForeignMarkings pending_foreign_markings_; - - // Created on the IO thread, but only used on the DB thread. - AppCacheDatabase* database_; - - // TODO(michaeln): use a disk_cache per group (manifest or group_id). - scoped_ptr<disk_cache::Backend> disk_cache_; - - // Used to short-circuit certain operations without having to schedule - // any tasks on the background database thread. - std::set<GURL> origins_with_groups_; - std::deque<Task*> pending_simple_tasks_; - ScopedRunnableMethodFactory<AppCacheStorageImpl> method_factory_; + FilePath cache_directory_; }; } // namespace appcache diff --git a/webkit/appcache/appcache_storage_impl_unittest.cc b/webkit/appcache/appcache_storage_impl_unittest.cc deleted file mode 100644 index 1db4aa8..0000000 --- a/webkit/appcache/appcache_storage_impl_unittest.cc +++ /dev/null @@ -1,1007 +0,0 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/message_loop.h" -#include "base/thread.h" -#include "base/waitable_event.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "webkit/appcache/appcache.h" -#include "webkit/appcache/appcache_database.h" -#include "webkit/appcache/appcache_entry.h" -#include "webkit/appcache/appcache_group.h" -#include "webkit/appcache/appcache_service.h" -#include "webkit/appcache/appcache_storage_impl.h" -#include "webkit/tools/test_shell/simple_appcache_system.h" - -namespace appcache { - -namespace { - -const base::TimeTicks kZeroTimeTicks; -const GURL kManifestUrl("http://blah/manifest"); -const GURL kManifestUrl2("http://blah/manifest2"); -const GURL kEntryUrl("http://blah/entry"); -const GURL kEntryUrl2("http://blah/entry2"); -const GURL kFallbackNamespace("http://blah/fallback_namespace/"); -const GURL kFallbackNamespace2("http://blah/fallback_namespace/longer"); -const GURL kFallbackTestUrl("http://blah/fallback_namespace/longer/test"); -const GURL kOnlineNamespace("http://blah/online_namespace"); - -// For the duration of this test case, we hijack the AppCacheThread API -// calls and implement them in terms of the io and db threads created here. - -scoped_ptr<base::Thread> io_thread; -scoped_ptr<base::Thread> db_thread; - -class TestThreadProvider : public SimpleAppCacheSystem::ThreadProvider { - public: - virtual bool PostTask( - int id, - const tracked_objects::Location& from_here, - Task* task) { - GetMessageLoop(id)->PostTask(from_here, task); - return true; - } - - virtual bool CurrentlyOn(int id) { - return MessageLoop::current() == GetMessageLoop(id); - } - - MessageLoop* GetMessageLoop(int id) { - DCHECK(io_thread.get() && db_thread.get()); - if (id == SimpleAppCacheSystem::IO_THREAD_ID) - return io_thread->message_loop(); - if (id == SimpleAppCacheSystem::DB_THREAD_ID) - return db_thread->message_loop(); - NOTREACHED() << "Invalid AppCacheThreadID value"; - return NULL; - } -}; - -TestThreadProvider thread_provider; - -} // namespace - -class AppCacheStorageImplTest : public testing::Test { - public: - class MockStorageDelegate : public AppCacheStorage::Delegate { - public: - explicit MockStorageDelegate(AppCacheStorageImplTest* test) - : loaded_cache_id_(0), stored_group_success_(false), - obsoleted_success_(false), found_cache_id_(kNoCacheId), - test_(test) { - } - - void OnCacheLoaded(AppCache* cache, int64 cache_id) { - loaded_cache_ = cache; - loaded_cache_id_ = cache_id; - test_->ScheduleNextTask(); - } - - void OnGroupLoaded(AppCacheGroup* group, const GURL& manifest_url) { - loaded_group_ = group; - loaded_manifest_url_ = manifest_url; - loaded_groups_newest_cache_ = group ? group->newest_complete_cache() - : NULL; - test_->ScheduleNextTask(); - } - - void OnGroupAndNewestCacheStored(AppCacheGroup* group, bool success) { - stored_group_ = group; - stored_group_success_ = success; - test_->ScheduleNextTask(); - } - - void OnGroupMadeObsolete(AppCacheGroup* group, bool success) { - obsoleted_group_ = group; - obsoleted_success_ = success; - test_->ScheduleNextTask(); - } - - void OnMainResponseFound(const GURL& url, const AppCacheEntry& entry, - const AppCacheEntry& fallback_entry, - int64 cache_id, const GURL& manifest_url) { - found_url_ = url; - found_entry_ = entry; - found_fallback_entry_ = fallback_entry; - found_cache_id_ = cache_id; - found_manifest_url_ = manifest_url; - test_->ScheduleNextTask(); - } - - scoped_refptr<AppCache> loaded_cache_; - int64 loaded_cache_id_; - scoped_refptr<AppCacheGroup> loaded_group_; - GURL loaded_manifest_url_; - scoped_refptr<AppCache> loaded_groups_newest_cache_; - scoped_refptr<AppCacheGroup> stored_group_; - bool stored_group_success_; - scoped_refptr<AppCacheGroup> obsoleted_group_; - bool obsoleted_success_; - GURL found_url_; - AppCacheEntry found_entry_; - AppCacheEntry found_fallback_entry_; - int64 found_cache_id_; - GURL found_manifest_url_; - AppCacheStorageImplTest* test_; - }; - - // Helper class run a test on our io_thread. The io_thread - // is spun up once and reused for all tests. - template <class Method> - class WrapperTask : public Task { - public: - WrapperTask(AppCacheStorageImplTest* test, Method method) - : test_(test), method_(method) { - } - - virtual void Run() { - test_->SetUpTest(); - - // Ensure InitTask execution prior to conducting a test. - test_->FlushDbThreadTasks(); - - // We also have to wait for InitTask completion call to be performed - // on the IO thread prior to running the test. Its guaranteed to be - // queued by this time. - MessageLoop::current()->PostTask(FROM_HERE, - NewRunnableFunction(&RunMethod, test_, method_)); - } - - static void RunMethod(AppCacheStorageImplTest* test, Method method) { - (test->*method)(); - } - - private: - AppCacheStorageImplTest* test_; - Method method_; - }; - - - static void SetUpTestCase() { - io_thread.reset(new base::Thread("AppCacheTest.IOThread")); - base::Thread::Options options(MessageLoop::TYPE_IO, 0); - ASSERT_TRUE(io_thread->StartWithOptions(options)); - - db_thread.reset(new base::Thread("AppCacheTest::DBThread")); - ASSERT_TRUE(db_thread->Start()); - - SimpleAppCacheSystem::set_thread_provider(&thread_provider); - } - - static void TearDownTestCase() { - SimpleAppCacheSystem::set_thread_provider(NULL); - io_thread.reset(NULL); - db_thread.reset(NULL); - } - - // Test harness -------------------------------------------------- - - AppCacheStorageImplTest() - : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { - } - - template <class Method> - void RunTestOnIOThread(Method method) { - test_finished_event_ .reset(new base::WaitableEvent(false, false)); - io_thread->message_loop()->PostTask( - FROM_HERE, new WrapperTask<Method>(this, method)); - test_finished_event_->Wait(); - } - - void SetUpTest() { - DCHECK(MessageLoop::current() == io_thread->message_loop()); - service_.reset(new AppCacheService); - service_->Initialize(FilePath()); - delegate_.reset(new MockStorageDelegate(this)); - } - - void TearDownTest() { - DCHECK(MessageLoop::current() == io_thread->message_loop()); - storage()->CancelDelegateCallbacks(delegate()); - group_ = NULL; - cache_ = NULL; - cache2_ = NULL; - delegate_.reset(); - service_.reset(); - FlushDbThreadTasks(); - } - - void TestFinished() { - // We unwind the stack prior to finishing up to let stack - // based objects get deleted. - DCHECK(MessageLoop::current() == io_thread->message_loop()); - MessageLoop::current()->PostTask(FROM_HERE, - method_factory_.NewRunnableMethod( - &AppCacheStorageImplTest::TestFinishedUnwound)); - } - - void TestFinishedUnwound() { - TearDownTest(); - test_finished_event_->Signal(); - } - - void PushNextTask(Task* task) { - task_stack_.push(task); - } - - void ScheduleNextTask() { - DCHECK(MessageLoop::current() == io_thread->message_loop()); - if (task_stack_.empty()) { - return; - } - MessageLoop::current()->PostTask(FROM_HERE, task_stack_.top()); - task_stack_.pop(); - } - - static void SignalEvent(base::WaitableEvent* event) { - event->Signal(); - } - - void FlushDbThreadTasks() { - // We pump a task thru the db thread to ensure any tasks previously - // scheduled on that thread have been performed prior to return. - base::WaitableEvent event(false, false); - db_thread->message_loop()->PostTask(FROM_HERE, - NewRunnableFunction(&AppCacheStorageImplTest::SignalEvent, - &event)); - event.Wait(); - } - - // LoadCache_Miss ---------------------------------------------------- - - void LoadCache_Miss() { - // Attempt to load a cache that doesn't exist. Should - // complete asyncly. - PushNextTask(method_factory_.NewRunnableMethod( - &AppCacheStorageImplTest::Verify_LoadCache_Miss)); - - storage()->LoadCache(111, delegate()); - EXPECT_NE(111, delegate()->loaded_cache_id_); - } - - void Verify_LoadCache_Miss() { - EXPECT_EQ(111, delegate()->loaded_cache_id_); - EXPECT_FALSE(delegate()->loaded_cache_); - TestFinished(); - } - - // LoadCache_NearHit ------------------------------------------------- - - void LoadCache_NearHit() { - // Attempt to load a cache that is currently in use - // and does not require loading from storage. This - // load should complete syncly. - - // Setup some preconditions. Make an 'unstored' cache for - // us to load. The ctor should put it in the working set. - int64 cache_id = storage()->NewCacheId(); - scoped_refptr<AppCache> cache = new AppCache(service(), cache_id); - - // Conduct the test. - storage()->LoadCache(cache_id, delegate()); - EXPECT_EQ(cache_id, delegate()->loaded_cache_id_); - EXPECT_EQ(cache.get(), delegate()->loaded_cache_.get()); - TestFinished(); - } - - // CreateGroup -------------------------------------------- - - void CreateGroupInEmptyOrigin() { - // Attempt to load a group that doesn't exist, one should - // be created for us, but not stored. - - // Since the origin has no groups, the storage class will respond - // syncly. - storage()->LoadOrCreateGroup(kManifestUrl, delegate()); - Verify_CreateGroup(); - } - - void CreateGroupInPopulatedOrigin() { - // Attempt to load a group that doesn't exist, one should - // be created for us, but not stored. - PushNextTask(method_factory_.NewRunnableMethod( - &AppCacheStorageImplTest::Verify_CreateGroup)); - - // Since the origin has groups, storage class will have to - // consult the database and completion will be async. - storage()->origins_with_groups_.insert(kManifestUrl.GetOrigin()); - - storage()->LoadOrCreateGroup(kManifestUrl, delegate()); - EXPECT_FALSE(delegate()->loaded_group_.get()); - } - - void Verify_CreateGroup() { - EXPECT_EQ(kManifestUrl, delegate()->loaded_manifest_url_); - EXPECT_TRUE(delegate()->loaded_group_.get()); - EXPECT_TRUE(delegate()->loaded_group_->HasOneRef()); - EXPECT_FALSE(delegate()->loaded_group_->newest_complete_cache()); - - // Should not have been stored in the database. - AppCacheDatabase::GroupRecord record; - EXPECT_FALSE(database()->FindGroup( - delegate()->loaded_group_->group_id(), &record)); - - TestFinished(); - } - - // LoadGroupAndCache_FarHit -------------------------------------- - - void LoadGroupAndCache_FarHit() { - // Attempt to load a cache that is not currently in use - // and does require loading from disk. This - // load should complete asyncly. - PushNextTask(method_factory_.NewRunnableMethod( - &AppCacheStorageImplTest::Verify_LoadCache_Far_Hit)); - - // Setup some preconditions. Create a group and newest cache that - // appear to be "stored" and "not currently in use". - MakeCacheAndGroup(kManifestUrl, 1, 1, true); - group_ = NULL; - cache_ = NULL; - - // Conduct the cache load test, completes async - storage()->LoadCache(1, delegate()); - } - - void Verify_LoadCache_Far_Hit() { - EXPECT_TRUE(delegate()->loaded_cache_); - EXPECT_TRUE(delegate()->loaded_cache_->HasOneRef()); - EXPECT_EQ(1, delegate()->loaded_cache_id_); - - // The group should also have been loaded. - EXPECT_TRUE(delegate()->loaded_cache_->owning_group()); - EXPECT_TRUE(delegate()->loaded_cache_->owning_group()->HasOneRef()); - EXPECT_EQ(1, delegate()->loaded_cache_->owning_group()->group_id()); - - // Drop things from the working set. - delegate()->loaded_cache_ = NULL; - EXPECT_FALSE(delegate()->loaded_group_); - - // Conduct the group load test, also complete asyncly. - PushNextTask(method_factory_.NewRunnableMethod( - &AppCacheStorageImplTest::Verify_LoadGroup_Far_Hit)); - - storage()->LoadOrCreateGroup(kManifestUrl, delegate()); - } - - void Verify_LoadGroup_Far_Hit() { - EXPECT_TRUE(delegate()->loaded_group_); - EXPECT_EQ(kManifestUrl, delegate()->loaded_manifest_url_); - EXPECT_TRUE(delegate()->loaded_group_->newest_complete_cache()); - delegate()->loaded_groups_newest_cache_ = NULL; - EXPECT_TRUE(delegate()->loaded_group_->HasOneRef()); - TestFinished(); - } - - // StoreNewGroup -------------------------------------- - - void StoreNewGroup() { - // Store a group and its newest cache. Should complete asyncly. - PushNextTask(method_factory_.NewRunnableMethod( - &AppCacheStorageImplTest::Verify_StoreNewGroup)); - - // Setup some preconditions. Create a group and newest cache that - // appear to be "unstored". - group_ = new AppCacheGroup( - service(), kManifestUrl, storage()->NewGroupId()); - cache_ = new AppCache(service(), storage()->NewCacheId()); - cache_->set_complete(true); - // Hold a ref to the cache simulate the UpdateJob holding that ref, - // and hold a ref to the group to simulate the CacheHost holding that ref. - - // Conduct the store test. - storage()->StoreGroupAndNewestCache(group_, cache_, delegate()); - EXPECT_FALSE(delegate()->stored_group_success_); - } - - void Verify_StoreNewGroup() { - EXPECT_TRUE(delegate()->stored_group_success_); - EXPECT_EQ(group_.get(), delegate()->stored_group_.get()); - EXPECT_EQ(cache_.get(), group_->newest_complete_cache()); - - // Should have been stored in the database. - AppCacheDatabase::GroupRecord group_record; - AppCacheDatabase::CacheRecord cache_record; - EXPECT_TRUE(database()->FindGroup(group_->group_id(), &group_record)); - EXPECT_TRUE(database()->FindCache(cache_->cache_id(), &cache_record)); - TestFinished(); - } - - // StoreExistingGroup -------------------------------------- - - void StoreExistingGroup() { - // Store a group and its newest cache. Should complete asyncly. - PushNextTask(method_factory_.NewRunnableMethod( - &AppCacheStorageImplTest::Verify_StoreExistingGroup)); - - // Setup some preconditions. Create a group and old complete cache - // that appear to be "stored" - MakeCacheAndGroup(kManifestUrl, 1, 1, true); - - // And a newest unstored complete cache. - cache2_ = new AppCache(service(), 2); - cache2_->set_complete(true); - - // Conduct the test. - storage()->StoreGroupAndNewestCache(group_, cache2_, delegate()); - EXPECT_FALSE(delegate()->stored_group_success_); - } - - void Verify_StoreExistingGroup() { - EXPECT_TRUE(delegate()->stored_group_success_); - EXPECT_EQ(group_.get(), delegate()->stored_group_.get()); - EXPECT_EQ(cache2_.get(), group_->newest_complete_cache()); - - // The new cache should have been stored in the database. - AppCacheDatabase::GroupRecord group_record; - AppCacheDatabase::CacheRecord cache_record; - EXPECT_TRUE(database()->FindGroup(1, &group_record)); - EXPECT_TRUE(database()->FindCache(2, &cache_record)); - - // The old cache should have been deleted - EXPECT_FALSE(database()->FindCache(1, &cache_record)); - TestFinished(); - } - - // StoreExistingGroupExistingCache ------------------------------- - - void StoreExistingGroupExistingCache() { - // Store a group with updates to its existing newest complete cache. - // Setup some preconditions. Create a group and a complete cache that - // appear to be "stored". - - // Setup some preconditions. Create a group and old complete cache - // that appear to be "stored" - MakeCacheAndGroup(kManifestUrl, 1, 1, true); - - // Change the cache. - base::TimeTicks now = base::TimeTicks::Now(); - cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::MASTER)); - cache_->set_update_time(now); - - PushNextTask(method_factory_.NewRunnableMethod( - &AppCacheStorageImplTest::Verify_StoreExistingGroupExistingCache, - now)); - - // Conduct the test. - EXPECT_EQ(cache_, group_->newest_complete_cache()); - storage()->StoreGroupAndNewestCache(group_, cache_, delegate()); - EXPECT_FALSE(delegate()->stored_group_success_); - } - - void Verify_StoreExistingGroupExistingCache( - base::TimeTicks expected_update_time) { - EXPECT_TRUE(delegate()->stored_group_success_); - EXPECT_EQ(cache_, group_->newest_complete_cache()); - - AppCacheDatabase::CacheRecord cache_record; - EXPECT_TRUE(database()->FindCache(1, &cache_record)); - EXPECT_EQ(1, cache_record.cache_id); - EXPECT_EQ(1, cache_record.group_id); - EXPECT_FALSE(cache_record.online_wildcard); - EXPECT_TRUE(expected_update_time == cache_record.update_time); - - std::vector<AppCacheDatabase::EntryRecord> entry_records; - EXPECT_TRUE(database()->FindEntriesForCache(1, &entry_records)); - EXPECT_EQ(1U, entry_records.size()); - EXPECT_EQ(1 , entry_records[0].cache_id); - EXPECT_EQ(kEntryUrl, entry_records[0].url); - EXPECT_EQ(AppCacheEntry::MASTER, entry_records[0].flags); - EXPECT_EQ(0, entry_records[0].response_id); - - TestFinished(); - } - - // MakeGroupObsolete ------------------------------- - - void MakeGroupObsolete() { - // Make a group obsolete, should complete asyncly. - PushNextTask(method_factory_.NewRunnableMethod( - &AppCacheStorageImplTest::Verify_MakeGroupObsolete)); - - // Setup some preconditions. Create a group and newest cache that - // appears to be "stored" and "currently in use". - MakeCacheAndGroup(kManifestUrl, 1, 1, true); - EXPECT_FALSE(storage()->origins_with_groups_.empty()); - - // Also insert some related records. - AppCacheDatabase::EntryRecord entry_record; - entry_record.cache_id = 1; - entry_record.flags = AppCacheEntry::FALLBACK; - entry_record.response_id = 1; - entry_record.url = kEntryUrl; - EXPECT_TRUE(database()->InsertEntry(&entry_record)); - - AppCacheDatabase::FallbackNameSpaceRecord fallback_namespace_record; - fallback_namespace_record.cache_id = 1; - fallback_namespace_record.fallback_entry_url = kEntryUrl; - fallback_namespace_record.namespace_url = kFallbackNamespace; - fallback_namespace_record.origin = kManifestUrl.GetOrigin(); - EXPECT_TRUE( - database()->InsertFallbackNameSpace(&fallback_namespace_record)); - - AppCacheDatabase::OnlineWhiteListRecord online_whitelist_record; - online_whitelist_record.cache_id = 1; - online_whitelist_record.namespace_url = kOnlineNamespace; - EXPECT_TRUE(database()->InsertOnlineWhiteList(&online_whitelist_record)); - - // Conduct the test. - storage()->MakeGroupObsolete(group_, delegate()); - EXPECT_FALSE(group_->is_obsolete()); - } - - void Verify_MakeGroupObsolete() { - EXPECT_TRUE(delegate()->obsoleted_success_); - EXPECT_EQ(group_.get(), delegate()->obsoleted_group_.get()); - EXPECT_TRUE(group_->is_obsolete()); - EXPECT_TRUE(storage()->origins_with_groups_.empty()); - - // The cache and group have been deleted from the database. - AppCacheDatabase::GroupRecord group_record; - AppCacheDatabase::CacheRecord cache_record; - EXPECT_FALSE(database()->FindGroup(1, &group_record)); - EXPECT_FALSE(database()->FindCache(1, &cache_record)); - - // The related records should have been deleted too. - std::vector<AppCacheDatabase::EntryRecord> entry_records; - database()->FindEntriesForCache(1, &entry_records); - EXPECT_TRUE(entry_records.empty()); - std::vector<AppCacheDatabase::FallbackNameSpaceRecord> fallback_records; - database()->FindFallbackNameSpacesForCache(1, &fallback_records); - EXPECT_TRUE(fallback_records.empty()); - std::vector<AppCacheDatabase::OnlineWhiteListRecord> whitelist_records; - database()->FindOnlineWhiteListForCache(1, &whitelist_records); - EXPECT_TRUE(whitelist_records.empty()); - - TestFinished(); - } - - // MarkEntryAsForeign ------------------------------- - - void MarkEntryAsForeign() { - // Setup some preconditions. Create a cache with an entry - // in storage and in the working set. - MakeCacheAndGroup(kManifestUrl, 1, 1, true); - cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::EXPLICIT)); - AppCacheDatabase::EntryRecord entry_record; - entry_record.cache_id = 1; - entry_record.url = kEntryUrl; - entry_record.flags = AppCacheEntry::EXPLICIT; - entry_record.response_id = 0; - EXPECT_TRUE(database()->InsertEntry(&entry_record)); - EXPECT_FALSE(cache_->GetEntry(kEntryUrl)->IsForeign()); - - // Conduct the test. - storage()->MarkEntryAsForeign(kEntryUrl, 1); - - // The entry in the working set should have been updated syncly. - EXPECT_TRUE(cache_->GetEntry(kEntryUrl)->IsForeign()); - EXPECT_TRUE(cache_->GetEntry(kEntryUrl)->IsExplicit()); - - // And the entry in storage should also be updated, but that - // happens asyncly on the db thread. - FlushDbThreadTasks(); - AppCacheDatabase::EntryRecord entry_record2; - EXPECT_TRUE(database()->FindEntry(1, kEntryUrl, &entry_record2)); - EXPECT_EQ(AppCacheEntry::EXPLICIT | AppCacheEntry::FOREIGN, - entry_record2.flags); - TestFinished(); - } - - // MarkEntryAsForeignWithLoadInProgress ------------------------------- - - void MarkEntryAsForeignWithLoadInProgress() { - PushNextTask(method_factory_.NewRunnableMethod( - &AppCacheStorageImplTest::Verify_MarkEntryAsForeignWithLoadInProgress)); - - // Setup some preconditions. Create a cache with an entry - // in storage, but not in the working set. - MakeCacheAndGroup(kManifestUrl, 1, 1, true); - cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::EXPLICIT)); - AppCacheDatabase::EntryRecord entry_record; - entry_record.cache_id = 1; - entry_record.url = kEntryUrl; - entry_record.flags = AppCacheEntry::EXPLICIT; - entry_record.response_id = 0; - EXPECT_TRUE(database()->InsertEntry(&entry_record)); - EXPECT_FALSE(cache_->GetEntry(kEntryUrl)->IsForeign()); - EXPECT_TRUE(cache_->HasOneRef()); - cache_ = NULL; - group_ = NULL; - - // Conduct the test, start a cache load, and prior to completion - // of that load, mark the entry as foreign. - storage()->LoadCache(1, delegate()); - storage()->MarkEntryAsForeign(kEntryUrl, 1); - } - - void Verify_MarkEntryAsForeignWithLoadInProgress() { - EXPECT_EQ(1, delegate()->loaded_cache_id_); - EXPECT_TRUE(delegate()->loaded_cache_.get()); - - // The entry in the working set should have been updated upon load. - EXPECT_TRUE(delegate()->loaded_cache_->GetEntry(kEntryUrl)->IsForeign()); - EXPECT_TRUE(delegate()->loaded_cache_->GetEntry(kEntryUrl)->IsExplicit()); - - // And the entry in storage should also be updated. - FlushDbThreadTasks(); - AppCacheDatabase::EntryRecord entry_record; - EXPECT_TRUE(database()->FindEntry(1, kEntryUrl, &entry_record)); - EXPECT_EQ(AppCacheEntry::EXPLICIT | AppCacheEntry::FOREIGN, - entry_record.flags); - TestFinished(); - } - - // FindNoMainResponse ------------------------------- - - void FindNoMainResponse() { - PushNextTask(method_factory_.NewRunnableMethod( - &AppCacheStorageImplTest::Verify_FindNoMainResponse)); - - // Conduct the test. - storage()->FindResponseForMainRequest(kEntryUrl, delegate()); - EXPECT_NE(kEntryUrl, delegate()->found_url_); - } - - void Verify_FindNoMainResponse() { - EXPECT_EQ(kEntryUrl, delegate()->found_url_); - EXPECT_TRUE(delegate()->found_manifest_url_.is_empty()); - EXPECT_EQ(kNoCacheId, delegate()->found_cache_id_); - EXPECT_EQ(kNoResponseId, delegate()->found_entry_.response_id()); - EXPECT_EQ(kNoResponseId, delegate()->found_fallback_entry_.response_id()); - EXPECT_EQ(0, delegate()->found_entry_.types()); - EXPECT_EQ(0, delegate()->found_fallback_entry_.types()); - TestFinished(); - } - - // BasicFindMainResponse ------------------------------- - - void BasicFindMainResponseInDatabase() { - BasicFindMainResponse(true); - } - - void BasicFindMainResponseInWorkingSet() { - BasicFindMainResponse(false); - } - - void BasicFindMainResponse(bool drop_from_working_set) { - PushNextTask(method_factory_.NewRunnableMethod( - &AppCacheStorageImplTest::Verify_BasicFindMainResponse)); - - // Setup some preconditions. Create a complete cache with an entry - // in storage. - MakeCacheAndGroup(kManifestUrl, 1, 1, true); - cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::EXPLICIT, 1)); - AppCacheDatabase::EntryRecord entry_record; - entry_record.cache_id = 1; - entry_record.url = kEntryUrl; - entry_record.flags = AppCacheEntry::EXPLICIT; - entry_record.response_id = 1; - EXPECT_TRUE(database()->InsertEntry(&entry_record)); - - // Optionally drop the cache/group pair from the working set. - if (drop_from_working_set) { - EXPECT_TRUE(cache_->HasOneRef()); - cache_ = NULL; - EXPECT_TRUE(group_->HasOneRef()); - group_ = NULL; - } - - // Conduct the test. - storage()->FindResponseForMainRequest(kEntryUrl, delegate()); - EXPECT_NE(kEntryUrl, delegate()->found_url_); - } - - void Verify_BasicFindMainResponse() { - EXPECT_EQ(kEntryUrl, delegate()->found_url_); - EXPECT_EQ(kManifestUrl, delegate()->found_manifest_url_); - EXPECT_EQ(1, delegate()->found_cache_id_); - EXPECT_EQ(1, delegate()->found_entry_.response_id()); - EXPECT_TRUE(delegate()->found_entry_.IsExplicit()); - EXPECT_FALSE(delegate()->found_fallback_entry_.has_response_id()); - TestFinished(); - } - - // BasicFindMainFallbackResponse ------------------------------- - - void BasicFindMainFallbackResponseInDatabase() { - BasicFindMainFallbackResponse(true); - } - - void BasicFindMainFallbackResponseInWorkingSet() { - BasicFindMainFallbackResponse(false); - } - - void BasicFindMainFallbackResponse(bool drop_from_working_set) { - PushNextTask(method_factory_.NewRunnableMethod( - &AppCacheStorageImplTest::Verify_BasicFindMainFallbackResponse)); - - // Setup some preconditions. Create a complete cache with a - // fallback namespace and entry. - MakeCacheAndGroup(kManifestUrl, 1, 1, true); - cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::FALLBACK, 1)); - cache_->AddEntry(kEntryUrl2, AppCacheEntry(AppCacheEntry::FALLBACK, 2)); - cache_->fallback_namespaces_.push_back( - FallbackNamespace(kFallbackNamespace2, kEntryUrl2)); - cache_->fallback_namespaces_.push_back( - FallbackNamespace(kFallbackNamespace, kEntryUrl)); - AppCacheDatabase::CacheRecord cache_record; - std::vector<AppCacheDatabase::EntryRecord> entries; - std::vector<AppCacheDatabase::FallbackNameSpaceRecord> fallbacks; - std::vector<AppCacheDatabase::OnlineWhiteListRecord> whitelists; - cache_->ToDatabaseRecords(group_, - &cache_record, &entries, &fallbacks, &whitelists); - EXPECT_TRUE(database()->InsertEntryRecords(entries)); - EXPECT_TRUE(database()->InsertFallbackNameSpaceRecords(fallbacks)); - EXPECT_TRUE(database()->InsertOnlineWhiteListRecords(whitelists)); - if (drop_from_working_set) { - EXPECT_TRUE(cache_->HasOneRef()); - cache_ = NULL; - EXPECT_TRUE(group_->HasOneRef()); - group_ = NULL; - } - - // Conduct the test. The test url is in both fallback namespace urls, - // but should match the longer of the two. - storage()->FindResponseForMainRequest(kFallbackTestUrl, delegate()); - EXPECT_NE(kFallbackTestUrl, delegate()->found_url_); - } - - void Verify_BasicFindMainFallbackResponse() { - EXPECT_EQ(kFallbackTestUrl, delegate()->found_url_); - EXPECT_EQ(kManifestUrl, delegate()->found_manifest_url_); - EXPECT_EQ(1, delegate()->found_cache_id_); - EXPECT_FALSE(delegate()->found_entry_.has_response_id()); - EXPECT_EQ(2, delegate()->found_fallback_entry_.response_id()); - EXPECT_TRUE(delegate()->found_fallback_entry_.IsFallback()); - TestFinished(); - } - - // FindMainResponseWithMultipleHits ------------------------------- - - void FindMainResponseWithMultipleHits() { - PushNextTask(method_factory_.NewRunnableMethod( - &AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits)); - - // Setup some preconditions. Create 2 complete caches with an entry - // for the same url. - - // The first cache, in the database but not in the working set. - MakeCacheAndGroup(kManifestUrl, 1, 1, true); - cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::EXPLICIT, 1)); - AppCacheDatabase::EntryRecord entry_record; - entry_record.cache_id = 1; - entry_record.url = kEntryUrl; - entry_record.flags = AppCacheEntry::EXPLICIT; - entry_record.response_id = 1; - EXPECT_TRUE(database()->InsertEntry(&entry_record)); - cache_ = NULL; - group_ = NULL; - - // The second cache, in the database and working set. - MakeCacheAndGroup(kManifestUrl2, 2, 2, true); - cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::EXPLICIT, 2)); - entry_record.cache_id = 2; - entry_record.url = kEntryUrl; - entry_record.flags = AppCacheEntry::EXPLICIT; - entry_record.response_id = 2; - EXPECT_TRUE(database()->InsertEntry(&entry_record)); - - // Conduct the test, we should find the response from the second cache - // since it's "in use". - storage()->FindResponseForMainRequest(kEntryUrl, delegate()); - EXPECT_NE(kEntryUrl, delegate()->found_url_); - } - - void Verify_FindMainResponseWithMultipleHits() { - EXPECT_EQ(kEntryUrl, delegate()->found_url_); - EXPECT_EQ(kManifestUrl2, delegate()->found_manifest_url_); - EXPECT_EQ(2, delegate()->found_cache_id_); - EXPECT_EQ(2, delegate()->found_entry_.response_id()); - EXPECT_TRUE(delegate()->found_entry_.IsExplicit()); - EXPECT_FALSE(delegate()->found_fallback_entry_.has_response_id()); - TestFinished(); - } - - // FindMainResponseExclusions ------------------------------- - - void FindMainResponseExclusionsInDatabase() { - FindMainResponseExclusions(true); - } - - void FindMainResponseExclusionsInWorkingSet() { - FindMainResponseExclusions(false); - } - - void FindMainResponseExclusions(bool drop_from_working_set) { - // Setup some preconditions. Create a complete cache with a - // foreign entry and an online namespace. - MakeCacheAndGroup(kManifestUrl, 1, 1, true); - cache_->AddEntry(kEntryUrl, - AppCacheEntry(AppCacheEntry::EXPLICIT | AppCacheEntry::FOREIGN, 1)); - cache_->online_whitelist_namespaces_.push_back(kOnlineNamespace); - AppCacheDatabase::EntryRecord entry_record; - entry_record.cache_id = 1; - entry_record.url = kEntryUrl; - entry_record.flags = AppCacheEntry::EXPLICIT | AppCacheEntry::FOREIGN; - entry_record.response_id = 1; - EXPECT_TRUE(database()->InsertEntry(&entry_record)); - AppCacheDatabase::OnlineWhiteListRecord whitelist_record; - whitelist_record.cache_id = 1; - whitelist_record.namespace_url = kOnlineNamespace; - EXPECT_TRUE(database()->InsertOnlineWhiteList(&whitelist_record)); - if (drop_from_working_set) { - cache_ = NULL; - group_ = NULL; - } - - // We should not find anything for the foreign entry. - PushNextTask(method_factory_.NewRunnableMethod( - &AppCacheStorageImplTest::Verify_NotFound, kEntryUrl, false)); - storage()->FindResponseForMainRequest(kEntryUrl, delegate()); - } - - void Verify_NotFound(GURL expected_url, bool test_finished) { - EXPECT_EQ(expected_url, delegate()->found_url_); - EXPECT_TRUE(delegate()->found_manifest_url_.is_empty()); - EXPECT_EQ(kNoCacheId, delegate()->found_cache_id_); - EXPECT_EQ(kNoResponseId, delegate()->found_entry_.response_id()); - EXPECT_EQ(kNoResponseId, delegate()->found_fallback_entry_.response_id()); - EXPECT_EQ(0, delegate()->found_entry_.types()); - EXPECT_EQ(0, delegate()->found_fallback_entry_.types()); - - if (!test_finished) { - // We should not find anything for the online namespace. - PushNextTask(method_factory_.NewRunnableMethod( - &AppCacheStorageImplTest::Verify_NotFound, kOnlineNamespace, true)); - storage()->FindResponseForMainRequest(kOnlineNamespace, delegate()); - return; - } - - TestFinished(); - } - - // Test case helpers -------------------------------------------------- - - AppCacheService* service() { - return service_.get(); - } - - AppCacheStorageImpl* storage() { - return static_cast<AppCacheStorageImpl*>(service()->storage()); - } - - AppCacheDatabase* database() { - return storage()->database_; - } - - MockStorageDelegate* delegate() { - return delegate_.get(); - } - - void MakeCacheAndGroup( - const GURL& manifest_url, int64 group_id, int64 cache_id, - bool add_to_database) { - group_ = new AppCacheGroup(service(), manifest_url, group_id); - cache_ = new AppCache(service(), cache_id); - cache_->set_complete(true); - group_->AddCache(cache_); - if (add_to_database) { - AppCacheDatabase::GroupRecord group_record; - group_record.group_id = group_id; - group_record.manifest_url = manifest_url; - group_record.origin = manifest_url.GetOrigin(); - EXPECT_TRUE(database()->InsertGroup(&group_record)); - AppCacheDatabase::CacheRecord cache_record; - cache_record.cache_id = cache_id; - cache_record.group_id = group_id; - cache_record.online_wildcard = false; - cache_record.update_time = kZeroTimeTicks; - EXPECT_TRUE(database()->InsertCache(&cache_record)); - storage()->origins_with_groups_.insert(manifest_url.GetOrigin()); - } - } - - // Data members -------------------------------------------------- - - ScopedRunnableMethodFactory<AppCacheStorageImplTest> method_factory_; - scoped_ptr<base::WaitableEvent> test_finished_event_; - std::stack<Task*> task_stack_; - scoped_ptr<AppCacheService> service_; - scoped_ptr<MockStorageDelegate> delegate_; - scoped_refptr<AppCacheGroup> group_; - scoped_refptr<AppCache> cache_; - scoped_refptr<AppCache> cache2_; -}; - - -TEST_F(AppCacheStorageImplTest, LoadCache_Miss) { - RunTestOnIOThread(&AppCacheStorageImplTest::LoadCache_Miss); -} - -TEST_F(AppCacheStorageImplTest, LoadCache_NearHit) { - RunTestOnIOThread(&AppCacheStorageImplTest::LoadCache_NearHit); -} - -TEST_F(AppCacheStorageImplTest, CreateGroupInEmptyOrigin) { - RunTestOnIOThread(&AppCacheStorageImplTest::CreateGroupInEmptyOrigin); -} - -TEST_F(AppCacheStorageImplTest, CreateGroupInPopulatedOrigin) { - RunTestOnIOThread(&AppCacheStorageImplTest::CreateGroupInPopulatedOrigin); -} - -TEST_F(AppCacheStorageImplTest, LoadGroupAndCache_FarHit) { - RunTestOnIOThread(&AppCacheStorageImplTest::LoadGroupAndCache_FarHit); -} - -TEST_F(AppCacheStorageImplTest, StoreNewGroup) { - RunTestOnIOThread(&AppCacheStorageImplTest::StoreNewGroup); -} - -TEST_F(AppCacheStorageImplTest, StoreExistingGroup) { - RunTestOnIOThread(&AppCacheStorageImplTest::StoreExistingGroup); -} - -TEST_F(AppCacheStorageImplTest, StoreExistingGroupExistingCache) { - RunTestOnIOThread(&AppCacheStorageImplTest::StoreExistingGroupExistingCache); -} - -TEST_F(AppCacheStorageImplTest, MakeGroupObsolete) { - RunTestOnIOThread(&AppCacheStorageImplTest::MakeGroupObsolete); -} - -TEST_F(AppCacheStorageImplTest, MarkEntryAsForeign) { - RunTestOnIOThread(&AppCacheStorageImplTest::MarkEntryAsForeign); -} - -TEST_F(AppCacheStorageImplTest, MarkEntryAsForeignWithLoadInProgress) { - RunTestOnIOThread( - &AppCacheStorageImplTest::MarkEntryAsForeignWithLoadInProgress); -} - -TEST_F(AppCacheStorageImplTest, FindNoMainResponse) { - RunTestOnIOThread(&AppCacheStorageImplTest::FindNoMainResponse); -} - -TEST_F(AppCacheStorageImplTest, BasicFindMainResponseInDatabase) { - RunTestOnIOThread( - &AppCacheStorageImplTest::BasicFindMainResponseInDatabase); -} - -TEST_F(AppCacheStorageImplTest, BasicFindMainResponseInWorkingSet) { - RunTestOnIOThread( - &AppCacheStorageImplTest::BasicFindMainResponseInWorkingSet); -} - -TEST_F(AppCacheStorageImplTest, BasicFindMainFallbackResponseInDatabase) { - RunTestOnIOThread( - &AppCacheStorageImplTest::BasicFindMainFallbackResponseInDatabase); -} - -TEST_F(AppCacheStorageImplTest, BasicFindMainFallbackResponseInWorkingSet) { - RunTestOnIOThread( - &AppCacheStorageImplTest::BasicFindMainFallbackResponseInWorkingSet); -} - -TEST_F(AppCacheStorageImplTest, FindMainResponseWithMultipleHits) { - RunTestOnIOThread( - &AppCacheStorageImplTest::FindMainResponseWithMultipleHits); -} - -TEST_F(AppCacheStorageImplTest, FindMainResponseExclusionsInDatabase) { - RunTestOnIOThread( - &AppCacheStorageImplTest::FindMainResponseExclusionsInDatabase); -} - -TEST_F(AppCacheStorageImplTest, FindMainResponseExclusionsInWorkingSet) { - RunTestOnIOThread( - &AppCacheStorageImplTest::FindMainResponseExclusionsInWorkingSet); -} - -// That's all folks! - -} // namespace appcache - diff --git a/webkit/appcache/appcache_thread.h b/webkit/appcache/appcache_thread.h index 7224d23..9f14b1c 100644 --- a/webkit/appcache/appcache_thread.h +++ b/webkit/appcache/appcache_thread.h @@ -5,11 +5,10 @@ #ifndef WEBKIT_APPCACHE_APPCACHE_THREAD_H_ #define WEBKIT_APPCACHE_APPCACHE_THREAD_H_ -#include "base/task.h" - namespace tracked_objects { class Location; } +class Task; namespace appcache { @@ -32,13 +31,6 @@ class AppCacheThread { Task* task); static bool CurrentlyOn(int id); - template <class T> - static bool DeleteSoon(int id, - const tracked_objects::Location& from_here, - T* object) { - return PostTask(id, from_here, new DeleteTask<T>(object)); - } - private: AppCacheThread(); ~AppCacheThread(); diff --git a/webkit/appcache/appcache_working_set.cc b/webkit/appcache/appcache_working_set.cc index 652116c..2b61ea3 100644 --- a/webkit/appcache/appcache_working_set.cc +++ b/webkit/appcache/appcache_working_set.cc @@ -14,7 +14,6 @@ namespace appcache { AppCacheWorkingSet::~AppCacheWorkingSet() { DCHECK(caches_.empty()); DCHECK(groups_.empty()); - DCHECK(groups_by_origin_.empty()); } void AppCacheWorkingSet::AddCache(AppCache* cache) { @@ -32,20 +31,10 @@ void AppCacheWorkingSet::AddGroup(AppCacheGroup* group) { const GURL& url = group->manifest_url(); DCHECK(groups_.find(url) == groups_.end()); groups_.insert(GroupMap::value_type(url, group)); - groups_by_origin_[url.GetOrigin()].insert(GroupMap::value_type(url, group)); } void AppCacheWorkingSet::RemoveGroup(AppCacheGroup* group) { - const GURL& url = group->manifest_url(); - groups_.erase(url); - - GURL origin_url = url.GetOrigin(); - GroupMap* groups_in_origin = GetMutableGroupsInOrigin(origin_url); - if (groups_in_origin) { - groups_in_origin->erase(url); - if (groups_in_origin->empty()) - groups_by_origin_.erase(origin_url); - } + groups_.erase(group->manifest_url()); } void AppCacheWorkingSet::AddResponseInfo(AppCacheResponseInfo* info) { diff --git a/webkit/appcache/appcache_working_set.h b/webkit/appcache/appcache_working_set.h index 479e74d..6785d50 100644 --- a/webkit/appcache/appcache_working_set.h +++ b/webkit/appcache/appcache_working_set.h @@ -20,8 +20,6 @@ class AppCacheResponseInfo; // currently in memory. class AppCacheWorkingSet { public: - typedef std::map<GURL, AppCacheGroup*> GroupMap; - ~AppCacheWorkingSet(); void AddCache(AppCache* cache); @@ -38,10 +36,6 @@ class AppCacheWorkingSet { return (it != groups_.end()) ? it->second : NULL; } - const GroupMap* GetGroupsInOrigin(const GURL& origin_url) { - return GetMutableGroupsInOrigin(origin_url); - } - void AddResponseInfo(AppCacheResponseInfo* response_info); void RemoveResponseInfo(AppCacheResponseInfo* response_info); AppCacheResponseInfo* GetResponseInfo(int64 id) { @@ -51,17 +45,10 @@ class AppCacheWorkingSet { private: typedef base::hash_map<int64, AppCache*> CacheMap; - typedef std::map<GURL, GroupMap> GroupsByOriginMap; + typedef std::map<GURL, AppCacheGroup*> GroupMap; typedef base::hash_map<int64, AppCacheResponseInfo*> ResponseInfoMap; - - GroupMap* GetMutableGroupsInOrigin(const GURL& origin_url) { - GroupsByOriginMap::iterator it = groups_by_origin_.find(origin_url); - return (it != groups_by_origin_.end()) ? &it->second : NULL; - } - CacheMap caches_; GroupMap groups_; - GroupsByOriginMap groups_by_origin_; // origin -> (manifest -> group) ResponseInfoMap response_infos_; }; diff --git a/webkit/appcache/mock_appcache_storage.cc b/webkit/appcache/mock_appcache_storage.cc index 44bcd12..214be249 100644 --- a/webkit/appcache/mock_appcache_storage.cc +++ b/webkit/appcache/mock_appcache_storage.cc @@ -124,6 +124,8 @@ void MockAppCacheStorage::MarkEntryAsForeign( if (entry) entry->add_types(AppCacheEntry::FOREIGN); } + // TODO(michaeln): in real storage update in storage, and if this cache is + // being loaded be sure to update the memory cache upon load completion. } void MockAppCacheStorage::MakeGroupObsolete( @@ -138,7 +140,7 @@ void MockAppCacheStorage::MakeGroupObsolete( } AppCacheResponseReader* MockAppCacheStorage::CreateResponseReader( - const GURL& manifest_url, int64 response_id) { + const GURL& origin, int64 response_id) { return new AppCacheResponseReader(response_id, disk_cache()); } @@ -201,6 +203,14 @@ void MockAppCacheStorage::ProcessStoreGroupAndNewestCache( if (delegate_ref->delegate) delegate_ref->delegate->OnGroupAndNewestCacheStored(group, true); + + // We don't bother with removing responses from 'mock' storage + // TODO(michaeln): for 'real' storage... + // std::set<int64> doomed_responses_ = responses from old caches + // std::set<int64> needed_responses_ = responses from newest cache + // foreach(needed_responses_) + // doomed_responses_.remove(needed_response_); + // DoomResponses(group->manifest_url(), doomed_responses_); } namespace { |