summaryrefslogtreecommitdiffstats
path: root/chrome/browser/thumbnail_store.cc
diff options
context:
space:
mode:
authormeelapshah@chromium.org <meelapshah@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-07-28 01:22:25 +0000
committermeelapshah@chromium.org <meelapshah@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-07-28 01:22:25 +0000
commitdaa82dc7442d26d9a50e342c0d9dcee43f287df8 (patch)
treebe3c211a383852579223f57be9c1ee13b84c1f6d /chrome/browser/thumbnail_store.cc
parentabaa71c990b2d9dd514e9f2eefb1d2cf7b720562 (diff)
downloadchromium_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.cc139
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();
}