diff options
author | meelapshah@chromium.org <meelapshah@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-07-28 01:22:25 +0000 |
---|---|---|
committer | meelapshah@chromium.org <meelapshah@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-07-28 01:22:25 +0000 |
commit | daa82dc7442d26d9a50e342c0d9dcee43f287df8 (patch) | |
tree | be3c211a383852579223f57be9c1ee13b84c1f6d /chrome/browser/thumbnail_store.cc | |
parent | abaa71c990b2d9dd514e9f2eefb1d2cf7b720562 (diff) | |
download | chromium_src-daa82dc7442d26d9a50e342c0d9dcee43f287df8.zip chromium_src-daa82dc7442d26d9a50e342c0d9dcee43f287df8.tar.gz chromium_src-daa82dc7442d26d9a50e342c0d9dcee43f287df8.tar.bz2 |
Make ThumbnailStore broadcast a notification when it has finished reading thumbnails from disk.
Make DOMUIThumbnailSource wait for this notification if ThumbnailStore isn't ready yet.
Also clean up some of the code.
Review URL: http://codereview.chromium.org/155911
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@21785 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/thumbnail_store.cc')
-rw-r--r-- | chrome/browser/thumbnail_store.cc | 139 |
1 files changed, 91 insertions, 48 deletions
diff --git a/chrome/browser/thumbnail_store.cc b/chrome/browser/thumbnail_store.cc index e6f0e99..4f30c62 100644 --- a/chrome/browser/thumbnail_store.cc +++ b/chrome/browser/thumbnail_store.cc @@ -26,7 +26,8 @@ ThumbnailStore::ThumbnailStore() : cache_(NULL), db_(NULL), hs_(NULL), - url_blacklist_(NULL) { + url_blacklist_(NULL), + disk_data_loaded_(false) { } ThumbnailStore::~ThumbnailStore() { @@ -34,8 +35,7 @@ ThumbnailStore::~ThumbnailStore() { DCHECK(hs_ == NULL); } -void ThumbnailStore::Init(const FilePath& db_name, - Profile* profile) { +void ThumbnailStore::Init(const FilePath& db_name, Profile* profile) { // Load thumbnails already in the database. g_browser_process->file_thread()->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this, &ThumbnailStore::InitializeFromDB, @@ -50,7 +50,9 @@ void ThumbnailStore::Init(const FilePath& db_name, // Get the list of most visited URLs and redirect information from the // HistoryService. - seconds_to_next_update_ = kInitialUpdateIntervalSecs; + most_visited_urls_.reset(new MostVisitedMap); + timer_.Start(base::TimeDelta::FromSeconds(kUpdateIntervalSecs), this, + &ThumbnailStore::UpdateURLData); UpdateURLData(); // Register to get notified when the history is cleared. @@ -139,8 +141,7 @@ void ThumbnailStore::Shutdown() { // for details. hs_ = NULL; - // The source of notifications is the Profile. We may outlive the Profile so - // we unregister for notifications here. + // De-register for notifications. registrar_.RemoveAll(); // Stop the timer to ensure that UpdateURLData is not called during shutdown. @@ -161,6 +162,11 @@ void ThumbnailStore::OnRedirectsForURLAvailable( if (!success) return; + DCHECK(redirect_urls_.get()); + + // If A -> B -> C is a redirect chain, then this function would be called + // with url=C and redirects = {B, A}. This is entered into the RedirectMap as + // A => {B -> C}. if (redirects->empty()) { (*redirect_urls_)[url] = new RefCountedVector<GURL>; } else { @@ -171,9 +177,20 @@ void ThumbnailStore::OnRedirectsForURLAvailable( } } +history::RedirectMap::iterator ThumbnailStore::GetRedirectIteratorForURL( + const GURL& url) const { + for (history::RedirectMap::iterator it = redirect_urls_->begin(); + it != redirect_urls_->end(); ++it) { + if (it->first == url || + (!it->second->data.empty() && it->second->data.back() == url)) + return it; + } + return redirect_urls_->end(); +} + void ThumbnailStore::Observe(NotificationType type, - const NotificationSource& source, - const NotificationDetails& details) { + const NotificationSource& source, + const NotificationDetails& details) { if (type.value != NotificationType::HISTORY_URLS_DELETED) { NOTREACHED(); return; @@ -183,37 +200,58 @@ void ThumbnailStore::Observe(NotificationType type, // If all history was cleared, clear all of our data and reset the update // timer. if (url_details->all_history) { - most_visited_urls_.reset(); - redirect_urls_.reset(); - cache_.reset(); - - timer_.Stop(); - seconds_to_next_update_ = kInitialUpdateIntervalSecs; - timer_.Start(base::TimeDelta::FromSeconds(seconds_to_next_update_), this, - &ThumbnailStore::UpdateURLData); + most_visited_urls_->clear(); + redirect_urls_->clear(); + cache_->clear(); + timer_.Reset(); } } +void ThumbnailStore::NotifyThumbnailStoreReady() { + NotificationService::current()->Notify( + NotificationType::THUMBNAIL_STORE_READY, + Source<ThumbnailStore>(this), + NotificationService::NoDetails()); +} + void ThumbnailStore::UpdateURLData() { + DCHECK(url_blacklist_); + int result_count = ThumbnailStore::kMaxCacheSize + url_blacklist_->GetSize(); hs_->QueryTopURLsAndRedirects(result_count, &consumer_, NewCallback(this, &ThumbnailStore::OnURLDataAvailable)); } -void ThumbnailStore::OnURLDataAvailable(std::vector<GURL>* urls, +void ThumbnailStore::OnURLDataAvailable(HistoryService::Handle handle, + bool success, + std::vector<GURL>* urls, history::RedirectMap* redirects) { + if (!success) + return; + DCHECK(urls); DCHECK(redirects); - most_visited_urls_.reset(new std::vector<GURL>(*urls)); + // Each element of |urls| is the start of a redirect chain. When thumbnails + // are stored from TabContents, the tails of the redirect chains are + // associated with the image. Since SetPageThumbnail is called frequently, we + // look up the tail end of each element in |urls| and insert that into the + // MostVisitedMap. This way SetPageThumbnail can more quickly check if a + // given url is in the most visited list. + most_visited_urls_->clear(); + for (size_t i = 0; i < urls->size(); ++i) { + history::RedirectMap::iterator it = redirects->find(urls->at(i)); + if (it->second->data.empty()) + (*most_visited_urls_)[urls->at(i)] = GURL(); + else + (*most_visited_urls_)[it->second->data.back()] = urls->at(i); + } redirect_urls_.reset(new history::RedirectMap(*redirects)); - CleanCacheData(); - // Schedule the next update. - if (seconds_to_next_update_ < kMaxUpdateIntervalSecs) - seconds_to_next_update_ *= 2; - timer_.Start(base::TimeDelta::FromSeconds(seconds_to_next_update_), this, - &ThumbnailStore::UpdateURLData); + if (IsReady()) + NotifyThumbnailStoreReady(); + + CleanCacheData(); } void ThumbnailStore::CleanCacheData() { @@ -228,26 +266,15 @@ void ThumbnailStore::CleanCacheData() { // be written to disk. for (Cache::iterator cache_it = cache_->begin(); cache_it != cache_->end();) { - const GURL* url = NULL; - // For each URL in the cache, search the RedirectMap for the originating - // URL. - for (history::RedirectMap::iterator it = redirect_urls_->begin(); - it != redirect_urls_->end(); ++it) { - if (cache_it->first == it->first || - (it->second->data.size() && - cache_it->first == it->second->data.back())) { - url = &it->first; - break; - } - } + history::RedirectMap::iterator redirect_it = + GetRedirectIteratorForURL(cache_it->first); + const GURL* url = redirect_it == redirect_urls_->end() ? + NULL : &redirect_it->first; // If this URL is blacklisted or not in the most visited list, mark it for // deletion. Otherwise, if the cache entry is dirty, mark it to be written // to disk. if (url == NULL || IsURLBlacklisted(*url) || !IsPopular(*url)) { - // Note that we don't check whether the cache entry is dirty or not. If - // it is not dirty, then the thumbnail exists on disk and must be - // deleted. If it is dirty, it may exist on disk so we delete it anyways. urls_to_delete->data.push_back(cache_it->first); cache_->erase(cache_it++); } else { @@ -271,6 +298,8 @@ void ThumbnailStore::CommitCacheToDB( if (!db_) return; + base::TimeTicks db_start = base::TimeTicks::Now(); + int rv = sqlite3_exec(db_, "BEGIN TRANSACTION", NULL, NULL, NULL); DCHECK(rv == SQLITE_OK) << "Failed to begin transaction"; @@ -292,7 +321,8 @@ void ThumbnailStore::CommitCacheToDB( it != data_to_save->end(); ++it) { SQLITE_UNIQUE_STATEMENT(statement, *statement_cache_, "INSERT OR REPLACE INTO thumbnails " - "(url, boring_score, good_clipping, at_top, time_taken, data) " + "(url, boring_score, good_clipping, " + "at_top, time_taken, data) " "VALUES (?,?,?,?,?,?)"); statement->bind_string(0, it->first.spec()); statement->bind_double(1, it->second.score_.boring_score); @@ -309,6 +339,9 @@ void ThumbnailStore::CommitCacheToDB( rv = sqlite3_exec(db_, "COMMIT", NULL, NULL, NULL); DCHECK(rv == SQLITE_OK) << "Failed to commit transaction"; + + base::TimeDelta delta = base::TimeTicks::Now() - db_start; + HISTOGRAM_TIMES("ThumbnailStore.WriteDBToDisk", delta); } void ThumbnailStore::InitializeFromDB(const FilePath& db_name, @@ -351,18 +384,23 @@ void ThumbnailStore::InitializeFromDB(const FilePath& db_name, } void ThumbnailStore::GetAllThumbnailsFromDisk(MessageLoop* cb_loop) { - ThumbnailStore::Cache* cache = new ThumbnailStore::Cache; + Cache* cache = new Cache; SQLITE_UNIQUE_STATEMENT(statement, *statement_cache_, "SELECT * FROM thumbnails"); while (statement->step() == SQLITE_ROW) { + // The URL GURL url(statement->column_string(0)); + + // The score. ThumbnailScore score(statement->column_double(1), // Boring score statement->column_bool(2), // Good clipping statement->column_bool(3), // At top base::Time::FromInternalValue( statement->column_int64(4))); // Time taken + + // The image. scoped_refptr<RefCountedBytes> data = new RefCountedBytes; if (statement->column_blob_as_vector(5, &data->data)) (*cache)[url] = CacheEntry(data, score, false); @@ -372,17 +410,23 @@ void ThumbnailStore::GetAllThumbnailsFromDisk(MessageLoop* cb_loop) { NewRunnableMethod(this, &ThumbnailStore::OnDiskDataAvailable, cache)); } -void ThumbnailStore::OnDiskDataAvailable(ThumbnailStore::Cache* cache) { +void ThumbnailStore::OnDiskDataAvailable(Cache* cache) { if (cache) cache_.reset(cache); + + disk_data_loaded_ = true; + if (IsReady()) + NotifyThumbnailStoreReady(); } bool ThumbnailStore::ShouldStoreThumbnailForURL(const GURL& url) const { - if (IsURLBlacklisted(url) || cache_->size() >= ThumbnailStore::kMaxCacheSize) + if (!cache_.get()) + return false; + + if (IsURLBlacklisted(url) || cache_->size() >= kMaxCacheSize) return false; - return most_visited_urls_->size() < ThumbnailStore::kMaxCacheSize || - IsPopular(url); + return IsPopular(url); } bool ThumbnailStore::IsURLBlacklisted(const GURL& url) const { @@ -397,7 +441,6 @@ std::wstring ThumbnailStore::GetDictionaryKeyForURL( } bool ThumbnailStore::IsPopular(const GURL& url) const { - return most_visited_urls_->end() != find(most_visited_urls_->begin(), - most_visited_urls_->end(), - url); + return most_visited_urls_->size() < kMaxCacheSize || + most_visited_urls_->find(url) != most_visited_urls_->end(); } |