history_backend.cc revision a93a17c8d99d686bd4a1511e5504e5e6cc9fcadf
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/history_backend.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm>
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <functional>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <list>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <map>
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <set>
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/basictypes.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/compiler_specific.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/file_util.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_vector.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/message_loop.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/histogram.h"
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/rand_util.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/string_util.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/time.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/utf_string_conversions.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/autocomplete/history_url_provider.h"
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/bookmarks/bookmark_service.h"
28a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#include "chrome/browser/favicon/imported_favicon_usage.h"
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/history/download_row.h"
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/history/history_db_task.h"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/history_notifications.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/history_publisher.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/in_memory_history_backend.h"
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/page_usage_data.h"
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/select_favicon_frames.h"
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/top_sites.h"
37b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "chrome/browser/history/typed_url_syncable_service.h"
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/visit_filter.h"
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_constants.h"
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_notification_types.h"
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/url_constants.h"
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "googleurl/src/gurl.h"
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/chromium_strings.h"
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/generated_resources.h"
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sql/error_delegate_util.h"
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/android/android_provider_backend.h"
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::Time;
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::TimeDelta;
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::TimeTicks;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* The HistoryBackend consists of a number of components:
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HistoryDatabase (stores past 3 months of history)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      URLDatabase (stores a list of URLs)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DownloadDatabase (stores a list of downloads)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VisitDatabase (stores a list of visits for the URLs)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VisitSegmentDatabase (stores groups of URLs for the most visited view).
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ArchivedDatabase (stores history older than 3 months)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      URLDatabase (stores a list of URLs)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DownloadDatabase (stores a list of downloads)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VisitDatabase (stores a list of visits for the URLs)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (this does not store visit segments as they expire after 3 mos.)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TextDatabaseManager (manages multiple text database for different times)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      TextDatabase (represents a single month of full-text index).
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ...more TextDatabase objects...
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ExpireHistoryBackend (manages moving things from HistoryDatabase to
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          the ArchivedDatabase and deleting)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace history {
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// How long we keep segment data for in days. Currently 3 months.
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This value needs to be greater or equal to
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// MostVisitedModel::kMostVisitedScope but we don't want to introduce a direct
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// dependency between MostVisitedModel and the history backend.
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kSegmentDataRetention = 90;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// How long we'll wait to do a commit, so that things are batched together.
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kCommitIntervalSeconds = 10;
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The amount of time before we re-fetch the favicon.
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kFaviconRefetchDays = 7;
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// GetSessionTabs returns all open tabs, or tabs closed kSessionCloseTimeWindow
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// seconds ago.
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kSessionCloseTimeWindowSecs = 10;
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The maximum number of items we'll allow in the redirect list before
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// deleting some.
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kMaxRedirectCount = 32;
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The number of days old a history entry can be before it is considered "old"
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// and is archived.
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kArchiveDaysThreshold = 90;
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Converts from PageUsageData to MostVisitedURL. |redirects| is a
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// list of redirects for this URL. Empty list means no redirects.
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MostVisitedURL MakeMostVisitedURL(const PageUsageData& page_data,
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  const RedirectList& redirects) {
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MostVisitedURL mv;
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mv.url = page_data.GetURL();
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mv.title = page_data.GetTitle();
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (redirects.empty()) {
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Redirects must contain at least the target url.
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mv.redirects.push_back(mv.url);
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mv.redirects = redirects;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (mv.redirects[mv.redirects.size() - 1] != mv.url) {
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // The last url must be the target url.
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mv.redirects.push_back(mv.url);
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return mv;
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This task is run on a timer so that commits happen at regular intervals
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// so they are batched together. The important thing about this class is that
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// it supports canceling of the task so the reference to the backend will be
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// freed. The problem is that when history is shutting down, there is likely
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to be one of these commits still pending and holding a reference.
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The backend can call Cancel to have this task release the reference. The
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// task will still run (if we ever get to processing the event before
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// shutdown), but it will not do anything.
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Note that this is a refcounted object and is not a task in itself. It should
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// be assigned to a RunnableMethod.
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(brettw): bug 1165182: This should be replaced with a
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// base::WeakPtrFactory which will handle everything automatically (like we do
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// in ExpireHistoryBackend).
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class CommitLaterTask : public base::RefCounted<CommitLaterTask> {
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit CommitLaterTask(HistoryBackend* history_backend)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : history_backend_(history_backend) {
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The backend will call this function if it is being destroyed so that we
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // release our reference.
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Cancel() {
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    history_backend_ = NULL;
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void RunCommit() {
154b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (history_backend_)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      history_backend_->Commit();
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  friend class base::RefCounted<CommitLaterTask>;
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~CommitLaterTask() {}
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<HistoryBackend> history_backend_;
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Handles querying first the main database, then the full text database if that
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// fails. It will optionally keep track of all URLs seen so duplicates can be
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// eliminated. This is used by the querying sub-functions.
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(brettw): This class may be able to be simplified or eliminated. After
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// this was written, QueryResults can efficiently look up by URL, so the need
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// for this extra set of previously queried URLs is less important.
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class HistoryBackend::URLQuerier {
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLQuerier(URLDatabase* main_db, URLDatabase* archived_db, bool track_unique)
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : main_db_(main_db),
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        archived_db_(archived_db),
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        track_unique_(track_unique) {
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // When we're tracking unique URLs, returns true if this URL has been
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // previously queried. Only call when tracking unique URLs.
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool HasURL(const GURL& url) {
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(track_unique_);
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return unique_urls_.find(url) != unique_urls_.end();
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool GetRowForURL(const GURL& url, URLRow* row) {
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!main_db_->GetRowForURL(url, row)) {
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!archived_db_ || !archived_db_->GetRowForURL(url, row)) {
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // This row is neither in the main nor the archived DB.
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (track_unique_)
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      unique_urls_.insert(url);
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLDatabase* main_db_;  // Guaranteed non-NULL.
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLDatabase* archived_db_;  // Possibly NULL.
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool track_unique_;
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // When track_unique_ is set, this is updated with every URL seen so far.
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::set<GURL> unique_urls_;
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(URLQuerier);
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// KillHistoryDatabaseErrorDelegate -------------------------------------------
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class KillHistoryDatabaseErrorDelegate : public sql::ErrorDelegate {
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit KillHistoryDatabaseErrorDelegate(HistoryBackend* backend)
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : backend_(backend),
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        scheduled_killing_database_(false) {
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // sql::ErrorDelegate implementation.
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual int OnError(int error,
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      sql::Connection* connection,
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      sql::Statement* stmt) OVERRIDE {
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Do not schedule killing database more than once. If the first time
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // failed, it is unlikely that a second time will be successful.
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!scheduled_killing_database_ && sql::IsErrorCatastrophic(error)) {
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      scheduled_killing_database_ = true;
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Don't just do the close/delete here, as we are being called by |db| and
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // that seems dangerous.
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      MessageLoop::current()->PostTask(
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          FROM_HERE,
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          base::Bind(&HistoryBackend::KillHistoryDatabase, backend_));
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return error;
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns true if the delegate has previously scheduled killing the database.
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool scheduled_killing_database() const {
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return scheduled_killing_database_;
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Do not increment the count on |HistoryBackend| as that would create a
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // circular reference (HistoryBackend -> HistoryDatabase -> Connection ->
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ErrorDelegate -> HistoryBackend).
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HistoryBackend* backend_;
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // True if the backend has previously scheduled killing the history database.
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool scheduled_killing_database_;
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(KillHistoryDatabaseErrorDelegate);
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// HistoryBackend --------------------------------------------------------------
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HistoryBackend::HistoryBackend(const base::FilePath& history_dir,
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               int id,
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               Delegate* delegate,
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               BookmarkService* bookmark_service)
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : delegate_(delegate),
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      id_(id),
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      history_dir_(history_dir),
267c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      expirer_(this, bookmark_service),
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      recent_redirects_(kMaxRedirectCount),
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      backend_destroy_message_loop_(NULL),
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      segment_queried_(false),
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bookmark_service_(bookmark_service) {
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HistoryBackend::~HistoryBackend() {
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!scheduled_commit_) << "Deleting without cleanup";
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ReleaseDBTasks();
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Release AndroidProviderBackend before other objects.
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  android_provider_backend_.reset();
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // First close the databases before optionally running the "destroy" task.
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CloseAllDatabases();
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!backend_destroy_task_.is_null()) {
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Notify an interested party (typically a unit test) that we're done.
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(backend_destroy_message_loop_);
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    backend_destroy_message_loop_->PostTask(FROM_HERE, backend_destroy_task_);
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  file_util::Delete(GetAndroidCacheFileName(), false);
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::Init(const std::string& languages, bool force_fail) {
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!force_fail)
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    InitImpl(languages);
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delegate_->DBLoaded(id_);
301b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  typed_url_syncable_service_.reset(new TypedUrlSyncableService(this));
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::SetOnBackendDestroyTask(MessageLoop* message_loop,
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             const base::Closure& task) {
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!backend_destroy_task_.is_null())
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(WARNING) << "Setting more than one destroy task, overriding";
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  backend_destroy_message_loop_ = message_loop;
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  backend_destroy_task_ = task;
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::Closing() {
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Any scheduled commit will have a reference to us, we must make it
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // release that reference before we can be destroyed.
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CancelScheduledCommit();
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Release our reference to the delegate, this reference will be keeping the
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // history service alive.
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delegate_.reset();
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::NotifyRenderProcessHostDestruction(const void* host) {
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tracker_.NotifyRenderProcessHostDestruction(host);
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath HistoryBackend::GetThumbnailFileName() const {
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return history_dir_.Append(chrome::kThumbnailsFilename);
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath HistoryBackend::GetFaviconsFileName() const {
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return history_dir_.Append(chrome::kFaviconsFilename);
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath HistoryBackend::GetArchivedFileName() const {
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return history_dir_.Append(chrome::kArchivedHistoryFilename);
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath HistoryBackend::GetAndroidCacheFileName() const {
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return history_dir_.Append(chrome::kAndroidCacheFilename);
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SegmentID HistoryBackend::GetLastSegmentID(VisitID from_visit) {
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set is used to detect referrer loops.  Should not happen, but can
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // if the database is corrupt.
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::set<VisitID> visit_set;
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitID visit_id = from_visit;
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (visit_id) {
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitRow row;
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!db_->GetRowForVisit(visit_id, &row))
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 0;
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (row.segment_id)
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return row.segment_id;  // Found a visit in this change with a segment.
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Check the referrer of this visit, if any.
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    visit_id = row.referring_visit;
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (visit_set.find(visit_id) != visit_set.end()) {
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED() << "Loop in referer chain, giving up";
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    visit_set.insert(visit_id);
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0;
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SegmentID HistoryBackend::UpdateSegments(
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url,
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitID from_visit,
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitID visit_id,
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::PageTransition transition_type,
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Time ts) {
374b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We only consider main frames.
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!content::PageTransitionIsMainFrame(transition_type))
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SegmentID segment_id = 0;
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::PageTransition t =
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::PageTransitionStripQualifier(transition_type);
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Are we at the beginning of a new segment?
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note that navigating to an existing entry (with back/forward) reuses the
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // same transition type.  We are not adding it as a new segment in that case
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // because if this was the target of a redirect, we might end up with
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 2 entries for the same final URL. Ex: User types google.net, gets
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // redirected to google.com. A segment is created for google.net. On
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // google.com users navigates through a link, then press back. That last
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // navigation is for the entry google.com transition typed. We end up adding
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // a segment for that one as well. So we end up with google.net and google.com
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // in the segement table, showing as 2 entries in the NTP.
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note also that we should still be updating the visit count for that segment
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // which we are not doing now. It should be addressed when
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // http://crbug.com/96860 is fixed.
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((t == content::PAGE_TRANSITION_TYPED ||
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       t == content::PAGE_TRANSITION_AUTO_BOOKMARK) &&
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (transition_type & content::PAGE_TRANSITION_FORWARD_BACK) == 0) {
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If so, create or get the segment.
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string segment_name = db_->ComputeSegmentName(url);
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLID url_id = db_->GetRowForURL(url, NULL);
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!url_id)
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 0;
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!(segment_id = db_->GetSegmentNamed(segment_name))) {
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!(segment_id = db_->CreateSegment(url_id, segment_name))) {
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NOTREACHED();
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return 0;
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Note: if we update an existing segment, we update the url used to
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // represent that segment in order to minimize stale most visited
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // images.
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_->UpdateSegmentRepresentationURL(segment_id, url_id);
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Note: it is possible there is no segment ID set for this visit chain.
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This can happen if the initial navigation wasn't AUTO_BOOKMARK or
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TYPED. (For example GENERATED). In this case this visit doesn't count
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // toward any segment.
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!(segment_id = GetLastSegmentID(from_visit)))
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 0;
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set the segment in the visit.
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->SetSegmentID(visit_id, segment_id)) {
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Finally, increase the counter for that segment / day.
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->IncreaseSegmentVisitCount(segment_id, ts, 1)) {
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return segment_id;
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::UpdateWithPageEndTime(const void* host,
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           int32 page_id,
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           const GURL& url,
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           Time end_ts) {
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Will be filled with the URL ID and the visit ID of the last addition.
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitID visit_id = tracker_.GetLastVisit(host, page_id, url);
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateVisitDuration(visit_id, end_ts);
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::UpdateVisitDuration(VisitID visit_id, const Time end_ts) {
451b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the starting visit_time for visit_id.
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitRow visit_row;
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (db_->GetRowForVisit(visit_id, &visit_row)) {
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We should never have a negative duration time even when time is skewed.
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    visit_row.visit_duration = end_ts > visit_row.visit_time ?
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        end_ts - visit_row.visit_time : TimeDelta::FromMicroseconds(0);
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_->UpdateVisitRow(visit_row);
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::AddPage(const HistoryAddPageArgs& request) {
465b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Will be filled with the URL ID and the visit ID of the last addition.
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::pair<URLID, VisitID> last_ids(0, tracker_.GetLastVisit(
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      request.id_scope, request.page_id, request.referrer));
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitID from_visit_id = last_ids.second;
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If a redirect chain is given, we expect the last item in that chain to be
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the final URL.
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(request.redirects.empty() ||
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         request.redirects.back() == request.url);
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the user is adding older history, we need to make sure our times
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // are correct.
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request.time < first_recorded_time_)
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    first_recorded_time_ = request.time;
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::PageTransition request_transition = request.transition;
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::PageTransition stripped_transition =
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::PageTransitionStripQualifier(request_transition);
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool is_keyword_generated =
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (stripped_transition == content::PAGE_TRANSITION_KEYWORD_GENERATED);
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the user is navigating to a not-previously-typed intranet hostname,
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // change the transition to TYPED so that the omnibox will learn that this is
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // a known host.
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool has_redirects = request.redirects.size() > 1;
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (content::PageTransitionIsMainFrame(request_transition) &&
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (stripped_transition != content::PAGE_TRANSITION_TYPED) &&
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !is_keyword_generated) {
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& origin_url(has_redirects ?
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        request.redirects[0] : request.url);
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (origin_url.SchemeIs(chrome::kHttpScheme) ||
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        origin_url.SchemeIs(chrome::kHttpsScheme) ||
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        origin_url.SchemeIs(chrome::kFtpScheme)) {
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::string host(origin_url.host());
503a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      size_t registry_length =
504a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)          net::registry_controlled_domains::GetRegistryLength(
505a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)              host,
506a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)              net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES,
507a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)              net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
508a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      if (registry_length == 0 && !db_->IsTypedHost(host)) {
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        stripped_transition = content::PAGE_TRANSITION_TYPED;
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        request_transition =
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            content::PageTransitionFromInt(
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                stripped_transition |
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                content::PageTransitionGetQualifier(request_transition));
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!has_redirects) {
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The single entry is both a chain start and end.
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::PageTransition t = content::PageTransitionFromInt(
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        request_transition |
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        content::PAGE_TRANSITION_CHAIN_START |
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        content::PAGE_TRANSITION_CHAIN_END);
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No redirect case (one element means just the page itself).
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    last_ids = AddPageVisit(request.url, request.time,
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            last_ids.second, t, request.visit_source);
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Update the segment for this visit. KEYWORD_GENERATED visits should not
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // result in changing most visited, so we don't update segments (most
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // visited db).
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!is_keyword_generated) {
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      UpdateSegments(request.url, from_visit_id, last_ids.second, t,
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     request.time);
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Update the referrer's duration.
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      UpdateVisitDuration(from_visit_id, request.time);
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Redirect case. Add the redirect chain.
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::PageTransition redirect_info =
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        content::PAGE_TRANSITION_CHAIN_START;
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RedirectList redirects = request.redirects;
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (redirects[0].SchemeIs(chrome::kAboutScheme)) {
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // When the redirect source + referrer is "about" we skip it. This
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // happens when a page opens a new frame/window to about:blank and then
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // script sets the URL to somewhere else (used to hide the referrer). It
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // would be nice to keep all these redirects properly but we don't ever
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // see the initial about:blank load, so we don't know where the
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // subsequent client redirect came from.
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      //
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // In this case, we just don't bother hooking up the source of the
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // redirects, so we remove it.
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      redirects.erase(redirects.begin());
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (request_transition & content::PAGE_TRANSITION_CLIENT_REDIRECT) {
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      redirect_info = content::PAGE_TRANSITION_CLIENT_REDIRECT;
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // The first entry in the redirect chain initiated a client redirect.
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We don't add this to the database since the referrer is already
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // there, so we skip over it but change the transition type of the first
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // transition to client redirect.
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      //
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // The referrer is invalid when restoring a session that features an
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // https tab that redirects to a different host or to http. In this
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // case we don't need to reconnect the new redirect with the existing
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // chain.
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (request.referrer.is_valid()) {
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        DCHECK(request.referrer == redirects[0]);
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        redirects.erase(redirects.begin());
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // If the navigation entry for this visit has replaced that for the
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // first visit, remove the CHAIN_END marker from the first visit. This
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // can be called a lot, for example, the page cycler, and most of the
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // time we won't have changed anything.
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        VisitRow visit_row;
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (request.did_replace_entry &&
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            db_->GetRowForVisit(last_ids.second, &visit_row) &&
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            visit_row.transition & content::PAGE_TRANSITION_CHAIN_END) {
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          visit_row.transition = content::PageTransitionFromInt(
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              visit_row.transition & ~content::PAGE_TRANSITION_CHAIN_END);
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          db_->UpdateVisitRow(visit_row);
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t redirect_index = 0; redirect_index < redirects.size();
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         redirect_index++) {
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::PageTransition t =
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          content::PageTransitionFromInt(stripped_transition | redirect_info);
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // If this is the last transition, add a CHAIN_END marker
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (redirect_index == (redirects.size() - 1)) {
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        t = content::PageTransitionFromInt(
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            t | content::PAGE_TRANSITION_CHAIN_END);
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Record all redirect visits with the same timestamp. We don't display
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // them anyway, and if we ever decide to, we can reconstruct their order
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // from the redirect chain.
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      last_ids = AddPageVisit(redirects[redirect_index],
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              request.time, last_ids.second,
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              t, request.visit_source);
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (t & content::PAGE_TRANSITION_CHAIN_START) {
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Update the segment for this visit.
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        UpdateSegments(redirects[redirect_index],
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       from_visit_id, last_ids.second, t, request.time);
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Update the visit_details for this visit.
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        UpdateVisitDuration(from_visit_id, request.time);
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Subsequent transitions in the redirect list must all be server
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // redirects.
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      redirect_info = content::PAGE_TRANSITION_SERVER_REDIRECT;
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Last, save this redirect chain for later so we can set titles & favicons
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // on the redirected pages properly. It is indexed by the destination page.
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    recent_redirects_.Put(request.url, redirects);
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(brettw) bug 1140015: Add an "add page" notification so the history
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // views can keep in sync.
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Add the last visit to the tracker so we can get outgoing transitions.
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(evanm): Due to http://b/1194536 we lose the referrers of a subframe
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // navigation anyway, so last_visit_id is always zero for them.  But adding
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // them here confuses main frame history, so we skip them for now.
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (stripped_transition != content::PAGE_TRANSITION_AUTO_SUBFRAME &&
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      stripped_transition != content::PAGE_TRANSITION_MANUAL_SUBFRAME &&
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !is_keyword_generated) {
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tracker_.AddVisit(request.id_scope, request.page_id, request.url,
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      last_ids.second);
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
637b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (text_database_) {
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    text_database_->AddPageURL(request.url, last_ids.first, last_ids.second,
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               request.time);
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::InitImpl(const std::string& languages) {
646b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  DCHECK(!db_) << "Initializing HistoryBackend twice";
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // In the rare case where the db fails to initialize a dialog may get shown
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the blocks the caller, yet allows other messages through. For this reason
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // we only set db_ to the created database if creation is successful. That
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // way other methods won't do anything as db_ is still NULL.
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TimeTicks beginning_time = TimeTicks::Now();
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Compute the file names. Note that the index file can be removed when the
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // text db manager is finished being hooked up.
6562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath history_name = history_dir_.Append(chrome::kHistoryFilename);
6572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath thumbnail_name = GetThumbnailFileName();
6582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath archived_name = GetArchivedFileName();
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // History database.
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_.reset(new HistoryDatabase());
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |HistoryDatabase::Init| takes ownership of |error_delegate|.
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  KillHistoryDatabaseErrorDelegate* error_delegate =
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new KillHistoryDatabaseErrorDelegate(this);
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::InitStatus status = db_->Init(history_name, error_delegate);
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (status) {
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case sql::INIT_OK:
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case sql::INIT_FAILURE: {
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // A NULL db_ will cause all calls on this object to notice this error
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // and to not continue. If the error delegate scheduled killing the
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // database, the task it posted has not executed yet. Try killing the
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // database now before we close it.
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bool kill_database = error_delegate->scheduled_killing_database();
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (kill_database)
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        KillHistoryDatabase();
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      UMA_HISTOGRAM_BOOLEAN("History.AttemptedToFixProfileError",
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            kill_database);
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delegate_->NotifyProfileError(id_, status);
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_.reset();
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Fill the in-memory database and send it back to the history service on the
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // main thread.
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  InMemoryHistoryBackend* mem_backend = new InMemoryHistoryBackend;
6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (mem_backend->Init(history_name, db_.get()))
6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delegate_->SetInMemoryBackend(id_, mem_backend);  // Takes ownership of
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                      // pointer.
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delete mem_backend;  // Error case, run without the in-memory DB.
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->BeginExclusiveMode();  // Must be after the mem backend read the data.
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create the history publisher which needs to be passed on to the text and
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // thumbnail databases for publishing history.
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  history_publisher_.reset(new HistoryPublisher());
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!history_publisher_->Init()) {
7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The init may fail when there are no indexers wanting our history.
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Hence no need to log the failure.
7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    history_publisher_.reset();
7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Full-text database. This has to be first so we can pass it to the
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // HistoryDatabase for migration.
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  text_database_.reset(new TextDatabaseManager(history_dir_,
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               db_.get(), db_.get()));
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!text_database_->Init(history_publisher_.get())) {
7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "Text database initialization failed, running without it.";
7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    text_database_.reset();
7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (db_->needs_version_17_migration()) {
7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // See needs_version_17_migration() decl for more. In this case, we want
7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // to erase all the text database files. This must be done after the text
7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // database manager has been initialized, since it knows about all the
7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // files it manages.
7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    text_database_->DeleteAll();
7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Thumbnail database.
7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_.reset(new ThumbnailDatabase());
7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->GetNeedsThumbnailMigration()) {
7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No convertion needed - use new filename right away.
7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_name = GetFaviconsFileName();
7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (thumbnail_db_->Init(thumbnail_name,
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          history_publisher_.get(),
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          db_.get()) != sql::INIT_OK) {
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Unlike the main database, we don't error out when the database is too
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // new because this error is much less severe. Generally, this shouldn't
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // happen since the thumbnail and main datbase versions should be in sync.
7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We'll just continue without thumbnails & favicons in this case or any
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // other error.
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "Could not initialize the thumbnail database.";
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_.reset();
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (db_->GetNeedsThumbnailMigration()) {
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VLOG(1) << "Starting TopSites migration";
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delegate_->StartTopSitesMigration(id_);
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Archived database.
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (db_->needs_version_17_migration()) {
7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // See needs_version_17_migration() decl for more. In this case, we want
7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // to delete the archived database and need to do so before we try to
7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // open the file. We can ignore any error (maybe the file doesn't exist).
7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    file_util::Delete(archived_name, false);
7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  archived_db_.reset(new ArchivedDatabase());
7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!archived_db_->Init(archived_name)) {
7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "Could not initialize the archived database.";
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    archived_db_.reset();
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Generate the history and thumbnail database metrics only after performing
7612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // any migration work.
7622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (base::RandInt(1, 100) == 50) {
7632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Only do this computation sometimes since it can be expensive.
7642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    db_->ComputeDatabaseMetrics(history_name);
7652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    thumbnail_db_->ComputeDatabaseMetrics();
7662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
7672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Tell the expiration module about all the nice databases we made. This must
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // happen before db_->Init() is called since the callback ForceArchiveHistory
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // may need to expire stuff.
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // *sigh*, this can all be cleaned up when that migration code is removed.
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The main DB initialization should intuitively be first (not that it
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // actually matters) and the expirer should be set last.
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expirer_.SetDatabases(db_.get(), archived_db_.get(),
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        thumbnail_db_.get(), text_database_.get());
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Open the long-running transaction.
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->BeginTransaction();
780b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (thumbnail_db_)
7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_->BeginTransaction();
782b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (archived_db_)
7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    archived_db_->BeginTransaction();
784b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (text_database_)
7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    text_database_->BeginTransaction();
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the first item in our database.
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->GetStartDate(&first_recorded_time_);
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Start expiring old stuff.
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expirer_.StartArchivingOldStuff(TimeDelta::FromDays(kArchiveDaysThreshold));
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
794b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (thumbnail_db_) {
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    android_provider_backend_.reset(new AndroidProviderBackend(
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        GetAndroidCacheFileName(), db_.get(), thumbnail_db_.get(),
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        bookmark_service_, delegate_.get()));
7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HISTOGRAM_TIMES("History.InitTime",
8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  TimeTicks::Now() - beginning_time);
8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::CloseAllDatabases() {
806b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Commit the long-running transaction.
8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_->CommitTransaction();
8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_.reset();
8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
811b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (thumbnail_db_) {
8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_->CommitTransaction();
8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_.reset();
8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
815b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (archived_db_) {
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    archived_db_->CommitTransaction();
8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    archived_db_.reset();
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
819b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (text_database_) {
8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    text_database_->CommitTransaction();
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    text_database_.reset();
8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::pair<URLID, VisitID> HistoryBackend::AddPageVisit(
8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url,
8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Time time,
8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitID referring_visit,
8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::PageTransition transition,
8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitSource visit_source) {
8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Top-level frame navigations are visible, everything else is hidden
8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool new_hidden = !content::PageTransitionIsMainFrame(transition);
8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // NOTE: This code must stay in sync with
8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ExpireHistoryBackend::ExpireURLsForVisits().
8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(pkasting): http://b/1148304 We shouldn't be marking so many URLs as
8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // typed, which would eliminate the need for this code.
8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int typed_increment = 0;
8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::PageTransition transition_type =
8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::PageTransitionStripQualifier(transition);
8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((transition_type == content::PAGE_TRANSITION_TYPED &&
8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !content::PageTransitionIsRedirect(transition)) ||
8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      transition_type == content::PAGE_TRANSITION_KEYWORD_GENERATED)
8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    typed_increment = 1;
8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // See if this URL is already in the DB.
8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLRow url_info(url);
8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLID url_id = db_->GetRowForURL(url, &url_info);
8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (url_id) {
8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Update of an existing row.
8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (content::PageTransitionStripQualifier(transition) !=
8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        content::PAGE_TRANSITION_RELOAD)
8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url_info.set_visit_count(url_info.visit_count() + 1);
8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (typed_increment)
8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url_info.set_typed_count(url_info.typed_count() + typed_increment);
856c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (url_info.last_visit() < time)
857c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      url_info.set_last_visit(time);
8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Only allow un-hiding of pages, never hiding.
8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!new_hidden)
8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url_info.set_hidden(false);
8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_->UpdateURLRow(url_id, url_info);
8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Addition of a new row.
8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_info.set_visit_count(1);
8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_info.set_typed_count(typed_increment);
8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_info.set_last_visit(time);
8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_info.set_hidden(new_hidden);
8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_id = db_->AddURL(url_info);
8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!url_id) {
8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED() << "Adding URL failed.";
8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return std::make_pair(0, 0);
8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_info.id_ = url_id;
8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We don't actually add the URL to the full text index at this point. It
8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // might be nice to do this so that even if we get no title or body, the
8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // user can search for URL components and get the page.
8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    //
8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // However, in most cases, we'll get at least a title and usually contents,
8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // and this add will be redundant, slowing everything down. As a result,
8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // we ignore this edge case.
8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Add the visit with the time to the database.
8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitRow visit_info(url_id, time, referring_visit, transition, 0);
8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitID visit_id = db_->AddVisit(&visit_info, visit_source);
8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NotifyVisitObservers(visit_info);
8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (visit_info.visit_time < first_recorded_time_)
8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    first_recorded_time_ = visit_info.visit_time;
8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Broadcast a notification of the visit.
8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (visit_id) {
897b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (typed_url_syncable_service_.get())
898b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      typed_url_syncable_service_->OnUrlVisited(transition, &url_info);
899b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLVisitedDetails* details = new URLVisitedDetails;
9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    details->transition = transition;
9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    details->row = url_info;
9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(meelapshah) Disabled due to potential PageCycler regression.
9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Re-enable this.
9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // GetMostRecentRedirectsTo(url, &details->redirects);
9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URL_VISITED, details);
9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VLOG(0) << "Failed to build visit insert statement:  "
9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            << "url_id = " << url_id;
9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return std::make_pair(url_id, visit_id);
9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::AddPagesWithDetails(const URLRows& urls,
9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         VisitSource visit_source) {
917b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<URLsModifiedDetails> modified(new URLsModifiedDetails);
9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (URLRows::const_iterator i = urls.begin(); i != urls.end(); ++i) {
9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!i->last_visit().is_null());
9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We will add to either the archived database or the main one depending on
9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // the date of the added visit.
9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLDatabase* url_database;
9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitDatabase* visit_database;
9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (IsExpiredVisitTime(i->last_visit())) {
929b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      if (!archived_db_)
9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;  // No archived database to save it to, just forget this.
9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url_database = archived_db_.get();
9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      visit_database = archived_db_.get();
9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url_database = db_.get();
9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      visit_database = db_.get();
9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLRow existing_url;
9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLID url_id = url_database->GetRowForURL(i->url(), &existing_url);
9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!url_id) {
9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Add the page if it doesn't exist.
9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url_id = url_database->AddURL(*i);
9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!url_id) {
9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NOTREACHED() << "Could not add row to DB";
9455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
9475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (i->typed_count() > 0) {
9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        modified->changed_urls.push_back(*i);
9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        modified->changed_urls.back().set_id(url_id);  // *i likely has |id_| 0.
9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Add the page to the full text index. This function is also used for
9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // importing. Even though we don't have page contents, we can at least
9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // add the title and URL to the index so they can be searched. We don't
9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // bother to delete any already-existing FTS entries for the URL, since
9585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // this is normally called on import.
9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    //
9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If you ever import *after* first run (selecting import from the menu),
9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // then these additional entries will "shadow" the originals when querying
9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // for the most recent match only, and the user won't get snippets. This is
9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // a very minor issue, and fixing it will make import slower, so we don't
9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // bother.
9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool has_indexed = false;
966b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (text_database_) {
9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We do not have to make it update the visit database, below, we will
9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // create the visit entry with the indexed flag set.
9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      has_indexed = text_database_->AddPageData(i->url(), url_id, 0,
9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                i->last_visit(),
9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                i->title(), string16());
9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Sync code manages the visits itself.
9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (visit_source != SOURCE_SYNCED) {
9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Make up a visit to correspond to the last visit to the page.
9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VisitRow visit_info(url_id, i->last_visit(), 0,
9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          content::PageTransitionFromInt(
9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              content::PAGE_TRANSITION_LINK |
9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              content::PAGE_TRANSITION_CHAIN_START |
9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              content::PAGE_TRANSITION_CHAIN_END), 0);
9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      visit_info.is_indexed = has_indexed;
9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!visit_database->AddVisit(&visit_info, visit_source)) {
9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NOTREACHED() << "Adding visit failed.";
9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NotifyVisitObservers(visit_info);
9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (visit_info.visit_time < first_recorded_time_)
9905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        first_recorded_time_ = visit_info.visit_time;
9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
994b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (typed_url_syncable_service_.get())
995b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    typed_url_syncable_service_->OnUrlsModified(&modified->changed_urls);
996b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
9975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Broadcast a notification for typed URLs that have been modified. This
9985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // will be picked up by the in-memory URL database on the main thread.
9995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
10005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(brettw) bug 1140015: Add an "add page" notification so the history
10015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // views can keep in sync.
10025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED,
10035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         modified.release());
10045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
10065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::IsExpiredVisitTime(const base::Time& time) {
10095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return time < expirer_.GetCurrentArchiveTime();
10105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::SetPageTitle(const GURL& url,
10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  const string16& title) {
1014b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
10155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
10165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Update the full text index.
1018b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (text_database_)
10195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    text_database_->AddPageTitle(url, title);
10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Search for recent redirects which should get the same title. We make a
10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // dummy list containing the exact URL visited if there are no redirects so
10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the processing below can be the same.
10245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  history::RedirectList dummy_list;
10255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  history::RedirectList* redirects;
10265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RedirectCache::iterator iter = recent_redirects_.Get(url);
10275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (iter != recent_redirects_.end()) {
10285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    redirects = &iter->second;
10295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This redirect chain should have the destination URL as the last item.
10315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!redirects->empty());
10325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(redirects->back() == url);
10335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
10345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No redirect chain stored, make up one containing the URL we want so we
10355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // can use the same logic below.
10365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dummy_list.push_back(url);
10375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    redirects = &dummy_list;
10385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<URLsModifiedDetails> details(new URLsModifiedDetails);
10415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < redirects->size(); i++) {
10425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLRow row;
10435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLID row_id = db_->GetRowForURL(redirects->at(i), &row);
10445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (row_id && row.title() != title) {
10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      row.set_title(title);
10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_->UpdateURLRow(row_id, row);
10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      details->changed_urls.push_back(row);
10485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Broadcast notifications for any URLs that have changed. This will
10525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // update the in-memory database and the InMemoryURLIndex.
10535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!details->changed_urls.empty()) {
1054b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (typed_url_syncable_service_.get())
1055b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      typed_url_syncable_service_->OnUrlsModified(&details->changed_urls);
10565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED,
10575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           details.release());
10585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ScheduleCommit();
10595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::AddPageNoVisitForBookmark(const GURL& url,
10635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               const string16& title) {
1064b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
10655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
10665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLRow url_info(url);
10685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLID url_id = db_->GetRowForURL(url, &url_info);
10695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (url_id) {
10705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // URL is already known, nothing to do.
10715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
10725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!title.empty()) {
10755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_info.set_title(title);
10765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
10775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_info.set_title(UTF8ToUTF16(url.spec()));
10785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  url_info.set_last_visit(Time::Now());
10815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Mark the page hidden. If the user types it in, it'll unhide.
10825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  url_info.set_hidden(true);
10835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->AddURL(url_info);
10855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::IterateURLs(
10882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const scoped_refptr<components::VisitedLinkDelegate::URLEnumerator>&
10892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    iterator) {
1090b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
10915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HistoryDatabase::URLEnumerator e;
10925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (db_->InitURLEnumeratorForEverything(&e)) {
10935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      URLRow info;
10945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      while (e.GetNextURL(&info)) {
10952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        iterator->OnURL(info.url());
10965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
10975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      iterator->OnComplete(true);  // Success.
10985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
10995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
11005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  iterator->OnComplete(false);  // Failure.
11025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetAllTypedURLs(URLRows* urls) {
1105b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_)
11065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return db_->GetAllTypedUrls(urls);
11075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
11085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetVisitsForURL(URLID id, VisitVector* visits) {
1111b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_)
11125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return db_->GetVisitsForURL(id, visits);
11135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
11145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetMostRecentVisitsForURL(URLID id,
11175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               int max_visits,
11185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               VisitVector* visits) {
1119b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_)
11205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return db_->GetMostRecentVisitsForURL(id, max_visits, visits);
11215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
11225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::UpdateURL(URLID id, const history::URLRow& url) {
1125b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_)
11265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return db_->UpdateURLRow(id, url);
11275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
11285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::AddVisits(const GURL& url,
11315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               const std::vector<VisitInfo>& visits,
11325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               VisitSource visit_source) {
1133b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
11345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (std::vector<VisitInfo>::const_iterator visit = visits.begin();
11355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         visit != visits.end(); ++visit) {
11365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!AddPageVisit(
11375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              url, visit->first, 0, visit->second, visit_source).first) {
11385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
11395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
11405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
11415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ScheduleCommit();
11425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
11435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
11455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::RemoveVisits(const VisitVector& visits) {
1148b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
11495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
11505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expirer_.ExpireVisits(visits);
11525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
11535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
11545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetVisitsSource(const VisitVector& visits,
11575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     VisitSourceMap* sources) {
1158b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
11595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
11605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->GetVisitsSource(visits, sources);
11625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
11635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetURL(const GURL& url, history::URLRow* url_row) {
1166b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_)
11675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return db_->GetRowForURL(url, url_row) != 0;
11685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
11695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::QueryURL(scoped_refptr<QueryURLRequest> request,
11725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              const GURL& url,
11735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              bool want_visits) {
11745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
11755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
11765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool success = false;
11785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLRow* row = &request->value.a;
11795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitVector* visits = &request->value.b;
1180b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
11815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (db_->GetRowForURL(url, row)) {
11825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Have a row.
11835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      success = true;
11845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Optionally query the visits.
11865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (want_visits)
11875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        db_->GetVisitsForURL(row->id(), visits);
11885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
11895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->ForwardResult(request->handle(), success, row, visits);
11915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1193b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)TypedUrlSyncableService* HistoryBackend::GetTypedUrlSyncableService() const {
1194b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  return typed_url_syncable_service_.get();
1195b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
1196b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
11975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Segment usage ---------------------------------------------------------------
11985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::DeleteOldSegmentData() {
1200b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_)
12015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_->DeleteSegmentData(Time::Now() -
12025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           TimeDelta::FromDays(kSegmentDataRetention));
12035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::QuerySegmentUsage(
12065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<QuerySegmentUsageRequest> request,
12075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Time from_time,
12085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int max_result_count) {
12095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
12105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
12115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1212b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
12135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_->QuerySegmentUsage(from_time, max_result_count, &request->value.get());
12145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If this is the first time we query segments, invoke
12165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // DeleteOldSegmentData asynchronously. We do this to cleanup old
12175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // entries.
12185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!segment_queried_) {
12195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      segment_queried_ = true;
12205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      MessageLoop::current()->PostTask(
12215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          FROM_HERE,
12225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          base::Bind(&HistoryBackend::DeleteOldSegmentData, this));
12235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
12245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->ForwardResult(request->handle(), &request->value.get());
12265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::IncreaseSegmentDuration(const GURL& url,
12292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                             base::Time time,
12302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                             base::TimeDelta delta) {
1231b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
12322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
12332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
12342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const std::string segment_name(VisitSegmentDatabase::ComputeSegmentName(url));
12352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SegmentID segment_id = db_->GetSegmentNamed(segment_name);
12362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!segment_id) {
12372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    URLID url_id = db_->GetRowForURL(url, NULL);
12382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!url_id)
12392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;
12402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    segment_id = db_->CreateSegment(url_id, segment_name);
12412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!segment_id)
12422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;
12432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
12442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SegmentDurationID duration_id;
12452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::TimeDelta total_delta;
12462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!db_->GetSegmentDuration(segment_id, time, &duration_id,
12472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                               &total_delta)) {
12482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    db_->CreateSegmentDuration(segment_id, time, delta);
12492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
12502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
12512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  total_delta += delta;
12522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  db_->SetSegmentDuration(duration_id, total_delta);
12532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
12542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
12552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::QuerySegmentDuration(
12562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_refptr<QuerySegmentUsageRequest> request,
12572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::Time from_time,
12582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int max_result_count) {
12592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (request->canceled())
12602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
12612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1262b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
12632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    db_->QuerySegmentDuration(from_time, max_result_count,
12642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              &request->value.get());
12652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
12662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  request->ForwardResult(request->handle(), &request->value.get());
12672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
12682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
12695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Keyword visits --------------------------------------------------------------
12705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::SetKeywordSearchTermsForURL(const GURL& url,
12725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                 TemplateURLID keyword_id,
12735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                 const string16& term) {
1274b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
12755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
12765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the ID for this URL.
12785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLRow url_row;
12795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->GetRowForURL(url, &url_row)) {
12805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // There is a small possibility the url was deleted before the keyword
12815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // was added. Ignore the request.
12825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
12835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->SetKeywordSearchTermsForURL(url_row.id(), keyword_id, term);
12865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // details is deleted by BroadcastNotifications.
12885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  KeywordSearchTermDetails* details = new KeywordSearchTermDetails;
12895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  details->url = url;
12905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  details->keyword_id = keyword_id;
12915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  details->term = term;
12925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BroadcastNotifications(
12935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      chrome::NOTIFICATION_HISTORY_KEYWORD_SEARCH_TERM_UPDATED, details);
12945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
12955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::DeleteAllSearchTermsForKeyword(
12985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TemplateURLID keyword_id) {
1299b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
13005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
13015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->DeleteAllSearchTermsForKeyword(keyword_id);
13035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(sky): bug 1168470. Need to move from archive dbs too.
13045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
13055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::GetMostRecentKeywordSearchTerms(
13085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<GetMostRecentKeywordSearchTermsRequest> request,
13095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TemplateURLID keyword_id,
13105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const string16& prefix,
13115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int max_count) {
13125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
13135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
13145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1315b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
13165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_->GetMostRecentKeywordSearchTerms(keyword_id, prefix, max_count,
13175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         &(request->value));
13185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
13195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->ForwardResult(request->handle(), &request->value);
13205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Downloads -------------------------------------------------------------------
13235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::GetNextDownloadId(int* id) {
1325b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_)
13262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *id = db_->next_download_id();
13275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Get all the download entries from the database.
13302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::QueryDownloads(std::vector<DownloadRow>* rows) {
1331b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_)
13322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    db_->QueryDownloads(rows);
13335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Update a particular download entry.
13362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::UpdateDownload(const history::DownloadRow& data) {
1337b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
13382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
13392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  db_->UpdateDownload(data);
13402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ScheduleCommit();
13415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::CreateDownload(const history::DownloadRow& history_info,
13442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    int64* db_handle) {
1345b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
13462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
13472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  *db_handle = db_->CreateDownload(history_info);
13482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ScheduleCommit();
13495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::RemoveDownloads(const std::set<int64>& handles) {
1352b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
13532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
13542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int downloads_count_before = db_->CountDownloads();
13552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::TimeTicks started_removing = base::TimeTicks::Now();
13562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // HistoryBackend uses a long-running Transaction that is committed
13572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // periodically, so this loop doesn't actually hit the disk too hard.
13582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (std::set<int64>::const_iterator it = handles.begin();
13592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       it != handles.end(); ++it) {
13602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    db_->RemoveDownload(*it);
13612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
13622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::TimeTicks finished_removing = base::TimeTicks::Now();
13632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int downloads_count_after = db_->CountDownloads();
13642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int num_downloads_deleted = downloads_count_before - downloads_count_after;
13652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (num_downloads_deleted >= 0) {
13662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    UMA_HISTOGRAM_COUNTS("Download.DatabaseRemoveDownloadsCount",
13672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                         num_downloads_deleted);
13682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::TimeDelta micros = (1000 * (finished_removing - started_removing));
13692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    UMA_HISTOGRAM_TIMES("Download.DatabaseRemoveDownloadsTime", micros);
13702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (num_downloads_deleted > 0) {
13712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      UMA_HISTOGRAM_TIMES("Download.DatabaseRemoveDownloadsTimePerRecord",
13722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                          (1000 * micros) / num_downloads_deleted);
13732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
13745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
13752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int num_downloads_not_deleted = handles.size() - num_downloads_deleted;
13762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (num_downloads_not_deleted >= 0) {
13772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    UMA_HISTOGRAM_COUNTS("Download.DatabaseRemoveDownloadsCountNotRemoved",
13782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                         num_downloads_not_deleted);
13792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
13802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ScheduleCommit();
13815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::QueryHistory(scoped_refptr<QueryHistoryRequest> request,
13845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  const string16& text_query,
13855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  const QueryOptions& options) {
13865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
13875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
13885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TimeTicks beginning_time = TimeTicks::Now();
13905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1391b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
13925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (text_query.empty()) {
13935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Basic history query for the main database.
13945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      QueryHistoryBasic(db_.get(), db_.get(), options, &request->value);
13955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Now query the archived database. This is a bit tricky because we don't
13975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // want to query it if the queried time range isn't going to find anything
13985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // in it.
13995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // TODO(brettw) bug 1171036: do blimpie querying for the archived database
14005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // as well.
14015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // if (archived_db_.get() &&
14025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      //     expirer_.GetCurrentArchiveTime() - TimeDelta::FromDays(7)) {
14035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
14045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Full text history query.
14055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      QueryHistoryFTS(text_query, options, &request->value);
14065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
14075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->ForwardResult(request->handle(), &request->value);
14105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_TIMES("History.QueryHistory",
14125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      TimeTicks::Now() - beginning_time);
14135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Basic time-based querying of history.
14165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::QueryHistoryBasic(URLDatabase* url_db,
14175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       VisitDatabase* visit_db,
14185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       const QueryOptions& options,
14195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       QueryResults* result) {
14205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // First get all visits.
14215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitVector visits;
14222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool has_more_results = visit_db->GetVisibleVisitsInRange(options, &visits);
14232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(static_cast<int>(visits.size()) <= options.EffectiveMaxCount());
14245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Now add them and the URL rows to the results.
14265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLResult url_result;
14275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < visits.size(); i++) {
14285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const VisitRow visit = visits[i];
14295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Add a result row for this visit, get the URL info from the DB.
14315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!url_db->GetURLRow(visit.url_id, &url_result)) {
14325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VLOG(0) << "Failed to get id " << visit.url_id
14335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              << " from history.urls.";
14345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;  // DB out of sync and URL doesn't exist, try to recover.
14355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
14365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!url_result.url().is_valid()) {
14385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VLOG(0) << "Got invalid URL from history.urls with id "
14395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              << visit.url_id << ":  "
14405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              << url_result.url().possibly_invalid_spec();
14415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;  // Don't report invalid URLs in case of corruption.
14425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
14435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The archived database may be out of sync with respect to starring,
14455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // titles, last visit date, etc. Therefore, we query the main DB if the
14465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // current URL database is not the main one.
14475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (url_db == db_.get()) {
14485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Currently querying the archived DB, update with the main database to
14495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // catch any interesting stuff. This will update it if it exists in the
14505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // main DB, and do nothing otherwise.
14515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_->GetRowForURL(url_result.url(), &url_result);
14525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
14535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_result.set_visit_time(visit.visit_time);
14555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1456c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Set whether the visit was blocked for a managed user by looking at the
1457c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // transition type.
1458c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    url_result.set_blocked_visit(
1459c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        (visit.transition & content::PAGE_TRANSITION_BLOCKED) != 0);
1460c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
14615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We don't set any of the query-specific parts of the URLResult, since
14625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // snippets and stuff don't apply to basic querying.
14635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result->AppendURLBySwapping(&url_result);
14645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!has_more_results && options.begin_time <= first_recorded_time_)
14675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result->set_reached_beginning(true);
14685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::QueryHistoryFTS(const string16& text_query,
14715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     const QueryOptions& options,
14725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     QueryResults* result) {
1473b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!text_database_)
14745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
14755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Full text query, first get all the FTS results in the time range.
14775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<TextDatabase::Match> fts_matches;
14785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Time first_time_searched;
14795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  text_database_->GetTextMatches(text_query, options,
14805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 &fts_matches, &first_time_searched);
14815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLQuerier querier(db_.get(), archived_db_.get(), true);
14835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Now get the row and visit information for each one.
14855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLResult url_result;  // Declare outside loop to prevent re-construction.
14865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < fts_matches.size(); i++) {
14875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (options.max_count != 0 &&
14885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        static_cast<int>(result->size()) >= options.max_count)
14895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;  // Got too many items.
14905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Get the URL, querying the main and archived databases as necessary. If
14925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // this is not found, the history and full text search databases are out
14935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // of sync and we give up with this result.
14945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!querier.GetRowForURL(fts_matches[i].url, &url_result))
14955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
14965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!url_result.url().is_valid())
14985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;  // Don't report invalid URLs in case of corruption.
14995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Copy over the FTS stuff that the URLDatabase doesn't know about.
15015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We do this with swap() to avoid copying, since we know we don't
15025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // need the original any more. Note that we override the title with the
15035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // one from FTS, since that will match the title_match_positions (the
15045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // FTS title and the history DB title may differ).
15055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_result.set_title(fts_matches[i].title);
15065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_result.title_match_positions_.swap(
15075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        fts_matches[i].title_match_positions);
15085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_result.snippet_.Swap(&fts_matches[i].snippet);
15095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The visit time also comes from the full text search database. Since it
15115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // has the time, we can avoid an extra query of the visits table.
15125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_result.set_visit_time(fts_matches[i].time);
15135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Add it to the vector, this will clear our |url_row| object as a
15155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // result of the swap.
15165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result->AppendURLBySwapping(&url_result);
15175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
15185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (first_time_searched <= first_recorded_time_)
15205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result->set_reached_beginning(true);
15215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Frontend to GetMostRecentRedirectsFrom from the history thread.
15245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::QueryRedirectsFrom(
15255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<QueryRedirectsRequest> request,
15265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url) {
15275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
15285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
15295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool success = GetMostRecentRedirectsFrom(url, &request->value);
15305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->ForwardResult(request->handle(), url, success, &request->value);
15315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::QueryRedirectsTo(
15345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<QueryRedirectsRequest> request,
15355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url) {
15365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
15375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
15385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool success = GetMostRecentRedirectsTo(url, &request->value);
15395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->ForwardResult(request->handle(), url, success, &request->value);
15405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::GetVisibleVisitCountToHost(
15435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<GetVisibleVisitCountToHostRequest> request,
15445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url) {
15455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
15465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
15475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int count = 0;
15485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Time first_visit;
15495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const bool success = db_.get() &&
15505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_->GetVisibleVisitCountToHost(url, &count, &first_visit);
15515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->ForwardResult(request->handle(), success, count, first_visit);
15525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::QueryTopURLsAndRedirects(
15555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<QueryTopURLsAndRedirectsRequest> request,
15565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int result_count) {
15575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
15585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
15595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1560b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_) {
15615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    request->ForwardResult(request->handle(), false, NULL, NULL);
15625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
15635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
15645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<GURL>* top_urls = &request->value.a;
15665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  history::RedirectMap* redirects = &request->value.b;
15675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedVector<PageUsageData> data;
15695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->QuerySegmentUsage(base::Time::Now() - base::TimeDelta::FromDays(90),
15705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result_count, &data.get());
15715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < data.size(); ++i) {
15735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    top_urls->push_back(data[i]->GetURL());
15745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RefCountedVector<GURL>* list = new RefCountedVector<GURL>;
15755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GetMostRecentRedirectsFrom(top_urls->back(), &list->data);
15765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (*redirects)[top_urls->back()] = list;
15775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
15785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->ForwardResult(request->handle(), true, top_urls, redirects);
15805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Will replace QueryTopURLsAndRedirectsRequest.
15835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::QueryMostVisitedURLs(
15845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<QueryMostVisitedURLsRequest> request,
15855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int result_count,
15865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int days_back) {
15875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
15885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
15895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1590b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_) {
15915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No History Database - return an empty list.
15925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    request->ForwardResult(request->handle(), MostVisitedURLList());
15935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
15945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
15955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MostVisitedURLList* result = &request->value;
15975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  QueryMostVisitedURLsImpl(result_count, days_back, result);
15985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->ForwardResult(request->handle(), *result);
15995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::QueryFilteredURLs(
16025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      scoped_refptr<QueryFilteredURLsRequest> request,
16035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      int result_count,
16045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const history::VisitFilter& filter,
16055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bool extended_info)  {
16065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
16075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
16085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::Time request_start = base::Time::Now();
16105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1611b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_) {
16125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No History Database - return an empty list.
16135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    request->ForwardResult(request->handle(), FilteredURLList());
16145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
16155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
16165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitVector visits;
16185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->GetDirectVisitsDuringTimes(filter, 0, &visits);
16195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::map<URLID, double> score_map;
16215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < visits.size(); ++i) {
16225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    score_map[visits[i].url_id] += filter.GetVisitScore(visits[i]);
16235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
16245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(georgey): experiment with visit_segment database granularity (it is
16265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // currently 24 hours) to use it directly instead of using visits database,
16275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // which is considerably slower.
16285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedVector<PageUsageData> data;
16295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  data.reserve(score_map.size());
16305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::map<URLID, double>::iterator it = score_map.begin();
16315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       it != score_map.end(); ++it) {
16325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PageUsageData* pud = new PageUsageData(it->first);
16335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pud->SetScore(it->second);
16345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    data.push_back(pud);
16355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
16365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Limit to the top |result_count| results.
16385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::sort(data.begin(), data.end(), PageUsageData::Predicate);
16392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (result_count && implicit_cast<int>(data.size()) > result_count)
16405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    data.resize(result_count);
16415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < data.size(); ++i) {
16435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLRow info;
16445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (db_->GetURLRow(data[i]->GetID(), &info)) {
16455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      data[i]->SetURL(info.url());
16465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      data[i]->SetTitle(info.title());
16475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
16485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
16495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FilteredURLList& result = request->value;
16515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < data.size(); ++i) {
16525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PageUsageData* current_data = data[i];
16535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FilteredURL url(*current_data);
16545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (extended_info) {
16565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VisitVector visits;
16575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_->GetVisitsForURL(current_data->GetID(), &visits);
16585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (visits.size() > 0) {
16595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        url.extended_info.total_visits = visits.size();
16605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        for (size_t i = 0; i < visits.size(); ++i) {
16615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          url.extended_info.duration_opened +=
16625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              visits[i].visit_duration.InSeconds();
16635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (visits[i].visit_time > url.extended_info.last_visit_time) {
16645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            url.extended_info.last_visit_time = visits[i].visit_time;
16655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          }
16665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
16675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // TODO(macourteau): implement the url.extended_info.visits stat.
16685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
16695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
16705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result.push_back(url);
16715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
16725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int delta_time = std::max(1, std::min(999,
16745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      static_cast<int>((base::Time::Now() - request_start).InMilliseconds())));
16755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STATIC_HISTOGRAM_POINTER_BLOCK(
16765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "NewTabPage.SuggestedSitesLoadTime",
16775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Add(delta_time),
16785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::LinearHistogram::FactoryGet("NewTabPage.SuggestedSitesLoadTime",
16795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          1, 1000, 100, base::Histogram::kUmaTargetedHistogramFlag));
16805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->ForwardResult(request->handle(), result);
16825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::QueryMostVisitedURLsImpl(int result_count,
16855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              int days_back,
16865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              MostVisitedURLList* result) {
1687b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
16885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
16895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedVector<PageUsageData> data;
16915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->QuerySegmentUsage(base::Time::Now() -
16925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         base::TimeDelta::FromDays(days_back),
16935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         result_count, &data.get());
16945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < data.size(); ++i) {
16965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PageUsageData* current_data = data[i];
16975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RedirectList redirects;
16985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GetMostRecentRedirectsFrom(current_data->GetURL(), &redirects);
16995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MostVisitedURL url = MakeMostVisitedURL(*current_data, redirects);
17005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result->push_back(url);
17015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
17025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::GetRedirectsFromSpecificVisit(
17055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitID cur_visit, history::RedirectList* redirects) {
17065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Follow any redirects from the given visit and add them to the list.
17075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // It *should* be impossible to get a circular chain here, but we check
17085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // just in case to avoid infinite loops.
17095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL cur_url;
17105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::set<VisitID> visit_set;
17115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  visit_set.insert(cur_visit);
17125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (db_->GetRedirectFromVisit(cur_visit, &cur_visit, &cur_url)) {
17135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (visit_set.find(cur_visit) != visit_set.end()) {
17145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED() << "Loop in visit chain, giving up";
17155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
17165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
17175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    visit_set.insert(cur_visit);
17185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    redirects->push_back(cur_url);
17195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
17205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::GetRedirectsToSpecificVisit(
17235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitID cur_visit,
17245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    history::RedirectList* redirects) {
17255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Follow redirects going to cur_visit. These are added to |redirects| in
17265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the order they are found. If a redirect chain looks like A -> B -> C and
17275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |cur_visit| = C, redirects will be {B, A} in that order.
1728b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
17295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
17305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL cur_url;
17325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::set<VisitID> visit_set;
17335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  visit_set.insert(cur_visit);
17345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (db_->GetRedirectToVisit(cur_visit, &cur_visit, &cur_url)) {
17355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (visit_set.find(cur_visit) != visit_set.end()) {
17365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED() << "Loop in visit chain, giving up";
17375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
17385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
17395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    visit_set.insert(cur_visit);
17405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    redirects->push_back(cur_url);
17415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
17425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetMostRecentRedirectsFrom(
17455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& from_url,
17465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    history::RedirectList* redirects) {
17475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  redirects->clear();
1748b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
17495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
17505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLID from_url_id = db_->GetRowForURL(from_url, NULL);
17525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitID cur_visit = db_->GetMostRecentVisitForURL(from_url_id, NULL);
17535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!cur_visit)
17545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;  // No visits for URL.
17555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetRedirectsFromSpecificVisit(cur_visit, redirects);
17575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
17585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetMostRecentRedirectsTo(
17615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& to_url,
17625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    history::RedirectList* redirects) {
17635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  redirects->clear();
1764b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
17655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
17665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLID to_url_id = db_->GetRowForURL(to_url, NULL);
17685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitID cur_visit = db_->GetMostRecentVisitForURL(to_url_id, NULL);
17695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!cur_visit)
17705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;  // No visits for URL.
17715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetRedirectsToSpecificVisit(cur_visit, redirects);
17735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
17745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::ScheduleAutocomplete(HistoryURLProvider* provider,
17775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          HistoryURLProviderParams* params) {
17785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ExecuteWithDB should handle the NULL database case.
17795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  provider->ExecuteWithDB(this, db_.get(), params);
17805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::SetPageContents(const GURL& url,
17835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     const string16& contents) {
17845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This is histogrammed in the text database manager.
1785b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!text_database_)
17865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
17875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  text_database_->AddPageContents(url, contents);
17885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::SetPageThumbnail(
17915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url,
17925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const gfx::Image* thumbnail,
17935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ThumbnailScore& score) {
1794b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_ || !thumbnail_db_)
17955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
17965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLRow url_row;
17985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLID url_id = db_->GetRowForURL(url, &url_row);
17995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (url_id) {
18005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_->SetPageThumbnail(url, url_id, thumbnail, score,
18015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    url_row.last_visit());
18025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
18035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
18055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
18065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::GetPageThumbnail(
18085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<GetPageThumbnailRequest> request,
18095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url) {
18105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
18115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
18125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<base::RefCountedBytes> data;
18145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetPageThumbnailDirectly(page_url, &data);
18155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->ForwardResult(request->handle(), data);
18175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
18185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::GetPageThumbnailDirectly(
18205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
18215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<base::RefCountedBytes>* data) {
1822b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (thumbnail_db_) {
18235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *data = new base::RefCountedBytes;
18245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Time the result.
18265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TimeTicks beginning_time = TimeTicks::Now();
18275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    history::RedirectList redirects;
18295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLID url_id;
18305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool success = false;
18315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If there are some redirects, try to get a thumbnail from the last
18335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // redirect destination.
18345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (GetMostRecentRedirectsFrom(page_url, &redirects) &&
18355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        !redirects.empty()) {
18365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if ((url_id = db_->GetRowForURL(redirects.back(), NULL)))
18375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        success = thumbnail_db_->GetPageThumbnail(url_id, &(*data)->data());
18385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
18395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If we don't have a thumbnail from redirects, try the URL directly.
18415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!success) {
18425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if ((url_id = db_->GetRowForURL(page_url, NULL)))
18435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        success = thumbnail_db_->GetPageThumbnail(url_id, &(*data)->data());
18445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
18455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // In this rare case, we start to mine the older redirect sessions
18475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // from the visit table to try to find a thumbnail.
18485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!success) {
18495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      success = GetThumbnailFromOlderRedirect(page_url, &(*data)->data());
18505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
18515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!success)
18535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *data = NULL;  // This will tell the callback there was an error.
18545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UMA_HISTOGRAM_TIMES("History.GetPageThumbnail",
18565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        TimeTicks::Now() - beginning_time);
18575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
18585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
18595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::MigrateThumbnailsDatabase() {
18615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If there is no History DB, we can't record that the migration was done.
18625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // It will be recorded on the next run.
1863b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
18645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If there is no thumbnail DB, we can still record a successful migration.
1865b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (thumbnail_db_) {
18665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      thumbnail_db_->RenameAndDropThumbnails(GetThumbnailFileName(),
18675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             GetFaviconsFileName());
18685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
18695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_->ThumbnailMigrationDone();
18705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
18715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
18725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetThumbnailFromOlderRedirect(
18745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
18755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<unsigned char>* data) {
18765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Look at a few previous visit sessions.
18775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitVector older_sessions;
18785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLID page_url_id = db_->GetRowForURL(page_url, NULL);
18795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const int kVisitsToSearchForThumbnail = 4;
18805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->GetMostRecentVisitsForURL(
18815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      page_url_id, kVisitsToSearchForThumbnail, &older_sessions);
18825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Iterate across all those previous visits, and see if any of the
18845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // final destinations of those redirect chains have a good thumbnail
18855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // for us.
18865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool success = false;
18875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (VisitVector::const_iterator it = older_sessions.begin();
18885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       !success && it != older_sessions.end(); ++it) {
18895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    history::RedirectList redirects;
18905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (it->visit_id) {
18915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetRedirectsFromSpecificVisit(it->visit_id, &redirects);
18925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!redirects.empty()) {
18945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        URLID url_id;
18955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if ((url_id = db_->GetRowForURL(redirects.back(), NULL)))
18965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          success = thumbnail_db_->GetPageThumbnail(url_id, data);
18975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
18985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
18995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
19005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return success;
19025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
19035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::GetFavicons(
19055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<GURL>& icon_urls,
19065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int icon_types,
19075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int desired_size_in_dip,
19082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<ui::ScaleFactor>& desired_scale_factors,
19092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::vector<FaviconBitmapResult>* bitmap_results) {
19102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  UpdateFaviconMappingsAndFetchImpl(NULL, icon_urls, icon_types,
19112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    desired_size_in_dip, desired_scale_factors,
19122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    bitmap_results);
19135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
19145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::GetFaviconsForURL(
19165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
19175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int icon_types,
19185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int desired_size_in_dip,
19192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<ui::ScaleFactor>& desired_scale_factors,
19202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::vector<FaviconBitmapResult>* bitmap_results) {
19212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(bitmap_results);
19225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetFaviconsFromDB(page_url, icon_types, desired_size_in_dip,
19232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    desired_scale_factors, bitmap_results);
19245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
19255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::GetFaviconForID(
19272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    FaviconID favicon_id,
19282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int desired_size_in_dip,
19292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ui::ScaleFactor desired_scale_factor,
19302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::vector<FaviconBitmapResult>* bitmap_results) {
19315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<FaviconID> favicon_ids;
19325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  favicon_ids.push_back(favicon_id);
19335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<ui::ScaleFactor> desired_scale_factors;
19345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  desired_scale_factors.push_back(desired_scale_factor);
19355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get results from DB.
19372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  GetFaviconBitmapResultsForBestMatch(favicon_ids,
19382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      desired_size_in_dip,
19392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      desired_scale_factors,
19402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      bitmap_results);
19415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
19425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::UpdateFaviconMappingsAndFetch(
19445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
19455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<GURL>& icon_urls,
19465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int icon_types,
19475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int desired_size_in_dip,
19482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<ui::ScaleFactor>& desired_scale_factors,
19492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::vector<FaviconBitmapResult>* bitmap_results) {
19502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  UpdateFaviconMappingsAndFetchImpl(&page_url, icon_urls, icon_types,
19512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    desired_size_in_dip, desired_scale_factors,
19522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    bitmap_results);
19535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
19545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::MergeFavicon(
19565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
19572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GURL& icon_url,
19585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    history::IconType icon_type,
19595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<base::RefCountedMemory> bitmap_data,
19605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const gfx::Size& pixel_size) {
1961b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!thumbnail_db_ || !db_)
19625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
19635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  FaviconID favicon_id = thumbnail_db_->GetFaviconIDForFaviconURL(icon_url,
19652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      icon_type, NULL);
19665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!favicon_id) {
19682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // There is no favicon at |icon_url|, create it.
19692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    favicon_id = thumbnail_db_->AddFavicon(icon_url, icon_type,
19702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                           GetDefaultFaviconSizes());
19712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
19725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<FaviconBitmapIDSize> bitmap_id_sizes;
19742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  thumbnail_db_->GetFaviconBitmapIDSizes(favicon_id, &bitmap_id_sizes);
19755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // If there is already a favicon bitmap of |pixel_size| at |icon_url|,
19772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // replace it.
19782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool bitmap_identical = false;
19792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool replaced_bitmap = false;
19802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < bitmap_id_sizes.size(); ++i) {
19812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (bitmap_id_sizes[i].pixel_size == pixel_size) {
19822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (IsFaviconBitmapDataEqual(bitmap_id_sizes[i].bitmap_id, bitmap_data)) {
19832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        thumbnail_db_->SetFaviconBitmapLastUpdateTime(
19842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            bitmap_id_sizes[i].bitmap_id, base::Time::Now());
19852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        bitmap_identical = true;
19862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      } else {
19872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        thumbnail_db_->SetFaviconBitmap(bitmap_id_sizes[i].bitmap_id,
19882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            bitmap_data, base::Time::Now());
19892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        replaced_bitmap = true;
19905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
19912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
19925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
19935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
19945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Create a vector of the pixel sizes of the favicon bitmaps currently at
19962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // |icon_url|.
19972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<gfx::Size> favicon_sizes;
19982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < bitmap_id_sizes.size(); ++i)
19992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    favicon_sizes.push_back(bitmap_id_sizes[i].pixel_size);
20005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!replaced_bitmap && !bitmap_identical) {
20022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Set the preexisting favicon bitmaps as expired as the preexisting favicon
20032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // bitmaps are not consistent with the merged in data.
20042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    thumbnail_db_->SetFaviconOutOfDate(favicon_id);
20055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Delete an arbitrary favicon bitmap to avoid going over the limit of
20072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // |kMaxFaviconBitmapsPerIconURL|.
20082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (bitmap_id_sizes.size() >= kMaxFaviconBitmapsPerIconURL) {
20092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      thumbnail_db_->DeleteFaviconBitmap(bitmap_id_sizes[0].bitmap_id);
20102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      favicon_sizes.erase(favicon_sizes.begin());
20112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
20122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    thumbnail_db_->AddFaviconBitmap(favicon_id, bitmap_data, base::Time::Now(),
20132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    pixel_size);
20142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    favicon_sizes.push_back(pixel_size);
20155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
20165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // A site may have changed the favicons that it uses for |page_url|.
20182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Example Scenario:
20192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //   page_url = news.google.com
20202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //   Intial State: www.google.com/favicon.ico 16x16, 32x32
20212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //   MergeFavicon(news.google.com, news.google.com/news_specific.ico, ...,
20222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //                ..., 16x16)
20232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //
20242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Difficulties:
20252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // 1. Sync requires that a call to GetFaviconsForURL() returns the
20262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //    |bitmap_data| passed into MergeFavicon().
20272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //    - It is invalid for the 16x16 bitmap for www.google.com/favicon.ico to
20282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //      stay mapped to news.google.com because it would be unclear which 16x16
20292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //      bitmap should be returned via GetFaviconsForURL().
20302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //
20312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // 2. www.google.com/favicon.ico may be mapped to more than just
20322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //    news.google.com (eg www.google.com).
20332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //    - The 16x16 bitmap cannot be deleted from www.google.com/favicon.ico
20342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //
20352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // To resolve these problems, we copy all of the favicon bitmaps previously
20362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // mapped to news.google.com (|page_url|) and add them to the favicon at
20372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // news.google.com/news_specific.ico (|icon_url|). The favicon sizes for
20382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // |icon_url| are set to default to indicate that |icon_url| has incomplete
20392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // / incorrect data.
20402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Difficlty 1: All but news.google.com/news_specific.ico are unmapped from
20412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //              news.google.com
20422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Difficulty 2: The favicon bitmaps for www.google.com/favicon.ico are not
20432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //               modified.
20445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<IconMapping> icon_mappings;
20462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  thumbnail_db_->GetIconMappingsForPageURL(page_url, icon_type, &icon_mappings);
20475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Copy the favicon bitmaps mapped to |page_url| to the favicon at |icon_url|
20492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // till the limit of |kMaxFaviconBitmapsPerIconURL| is reached.
20502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < icon_mappings.size(); ++i) {
20512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (favicon_sizes.size() >= kMaxFaviconBitmapsPerIconURL)
20522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
20535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (icon_mappings[i].icon_url == icon_url)
20552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      continue;
20565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::vector<FaviconBitmap> bitmaps_to_copy;
20582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    thumbnail_db_->GetFaviconBitmaps(icon_mappings[i].icon_id,
20592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                     &bitmaps_to_copy);
20602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (size_t j = 0; j < bitmaps_to_copy.size(); ++j) {
20612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // Do not add a favicon bitmap at a pixel size for which there is already
20622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // a favicon bitmap mapped to |icon_url|. The one there is more correct
20632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // and having multiple equally sized favicon bitmaps for |page_url| is
20642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // ambiguous in terms of GetFaviconsForURL().
20652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      std::vector<gfx::Size>::iterator it = std::find(favicon_sizes.begin(),
20662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          favicon_sizes.end(), bitmaps_to_copy[j].pixel_size);
20672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (it != favicon_sizes.end())
20682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        continue;
20692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
20702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // Add the favicon bitmap as expired as it is not consistent with the
20712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // merged in data.
20722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      thumbnail_db_->AddFaviconBitmap(favicon_id,
20732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          bitmaps_to_copy[j].bitmap_data, base::Time(),
20742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          bitmaps_to_copy[j].pixel_size);
20752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      favicon_sizes.push_back(bitmaps_to_copy[j].pixel_size);
20762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
20772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (favicon_sizes.size() >= kMaxFaviconBitmapsPerIconURL)
20782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        break;
20792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
20802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
20812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
20822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Update the favicon mappings such that only |icon_url| is mapped to
20832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // |page_url|.
20842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool mapping_changed = false;
20852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (icon_mappings.size() != 1 || icon_mappings[0].icon_url != icon_url) {
20862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::vector<FaviconID> favicon_ids;
20872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    favicon_ids.push_back(favicon_id);
20885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetFaviconMappingsForPageAndRedirects(page_url, icon_type, favicon_ids);
20892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    mapping_changed = true;
20905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
20915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (mapping_changed || !bitmap_identical)
20932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SendFaviconChangedNotificationForPageAndRedirects(page_url);
20945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
20955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
20965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::SetFavicons(
20985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
20995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IconType icon_type,
21002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<FaviconBitmapData>& favicon_bitmap_data) {
2101b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!thumbnail_db_ || !db_)
21025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
21035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(ValidateSetFaviconsParams(favicon_bitmap_data));
21055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Build map of FaviconBitmapData for each icon url.
21075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef std::map<GURL, std::vector<FaviconBitmapData> >
21085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BitmapDataByIconURL;
21095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BitmapDataByIconURL grouped_by_icon_url;
21105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < favicon_bitmap_data.size(); ++i) {
21115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& icon_url = favicon_bitmap_data[i].icon_url;
21125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    grouped_by_icon_url[icon_url].push_back(favicon_bitmap_data[i]);
21135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
21145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Track whether the method modifies or creates any favicon bitmaps, favicons
21162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // or icon mappings.
21172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool data_modified = false;
21182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
21195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<FaviconID> icon_ids;
21202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (BitmapDataByIconURL::const_iterator it = grouped_by_icon_url.begin();
21212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       it != grouped_by_icon_url.end(); ++it) {
21225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& icon_url = it->first;
21235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FaviconID icon_id =
21245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        thumbnail_db_->GetFaviconIDForFaviconURL(icon_url, icon_type, NULL);
21252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
21262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!icon_id) {
21272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // TODO(pkotwicz): Remove the favicon sizes attribute from
21282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // ThumbnailDatabase::AddFavicon().
21292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      icon_id = thumbnail_db_->AddFavicon(icon_url, icon_type,
21302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                          GetDefaultFaviconSizes());
21312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      data_modified = true;
21322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
21335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    icon_ids.push_back(icon_id);
21345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!data_modified)
21362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SetFaviconBitmaps(icon_id, it->second, &data_modified);
21372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else
21382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SetFaviconBitmaps(icon_id, it->second, NULL);
21395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
21405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  data_modified |=
21422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SetFaviconMappingsForPageAndRedirects(page_url, icon_type, icon_ids);
21435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (data_modified) {
21452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Send notification to the UI as an icon mapping, favicon, or favicon
21462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // bitmap was changed by this function.
21472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SendFaviconChangedNotificationForPageAndRedirects(page_url);
21482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
21495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
21505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
21515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::SetFaviconsOutOfDateForPage(const GURL& page_url) {
21535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<IconMapping> icon_mappings;
21545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2155b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!thumbnail_db_ ||
21565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !thumbnail_db_->GetIconMappingsForPageURL(page_url,
21575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                &icon_mappings))
21585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
21595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<IconMapping>::iterator m = icon_mappings.begin();
21615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       m != icon_mappings.end(); ++m) {
21625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_->SetFaviconOutOfDate(m->icon_id);
21635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
21645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
21655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
21665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::CloneFavicons(const GURL& old_page_url,
21685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   const GURL& new_page_url) {
2169b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!thumbnail_db_)
21705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
21715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Prevent cross-domain cloning.
21735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (old_page_url.GetOrigin() != new_page_url.GetOrigin())
21745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
21755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_->CloneIconMappings(old_page_url, new_page_url);
21775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
21785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
21795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::SetImportedFavicons(
21815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<ImportedFaviconUsage>& favicon_usage) {
2182b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_ || !thumbnail_db_)
21835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
21845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Time now = Time::Now();
21865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Track all URLs that had their favicons set or updated.
21885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::set<GURL> favicons_changed;
21895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < favicon_usage.size(); i++) {
21915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FaviconID favicon_id = thumbnail_db_->GetFaviconIDForFaviconURL(
21925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        favicon_usage[i].favicon_url, history::FAVICON, NULL);
21935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!favicon_id) {
21945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // This favicon doesn't exist yet, so we create it using the given data.
21955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // TODO(pkotwicz): Pass in real pixel size.
21965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      favicon_id = thumbnail_db_->AddFavicon(
21975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          favicon_usage[i].favicon_url,
21985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          history::FAVICON,
21995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          GetDefaultFaviconSizes(),
22005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          new base::RefCountedBytes(favicon_usage[i].png_data),
22015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          now,
22025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          gfx::Size());
22035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
22045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Save the mapping from all the URLs to the favicon.
22065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BookmarkService* bookmark_service = GetBookmarkService();
22075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (std::set<GURL>::const_iterator url = favicon_usage[i].urls.begin();
22085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         url != favicon_usage[i].urls.end(); ++url) {
22095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      URLRow url_row;
22105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!db_->GetRowForURL(*url, &url_row)) {
22115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // If the URL is present as a bookmark, add the url in history to
22125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // save the favicon mapping. This will match with what history db does
22135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // for regular bookmarked URLs with favicons - when history db is
22145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // cleaned, we keep an entry in the db with 0 visits as long as that
22155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // url is bookmarked.
22165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (bookmark_service && bookmark_service_->IsBookmarked(*url)) {
22175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          URLRow url_info(*url);
22185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          url_info.set_visit_count(0);
22195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          url_info.set_typed_count(0);
22205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          url_info.set_last_visit(base::Time());
22215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          url_info.set_hidden(false);
22225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          db_->AddURL(url_info);
22235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          thumbnail_db_->AddIconMapping(*url, favicon_id);
22245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          favicons_changed.insert(*url);
22255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
22265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
22275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!thumbnail_db_->GetIconMappingsForPageURL(*url, FAVICON, NULL)) {
22285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // URL is present in history, update the favicon *only* if it is not
22295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // set already.
22305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          thumbnail_db_->AddIconMapping(*url, favicon_id);
22315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          favicons_changed.insert(*url);
22325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
22335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
22345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
22355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
22365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!favicons_changed.empty()) {
22385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Send the notification about the changed favicon URLs.
22395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FaviconChangeDetails* changed_details = new FaviconChangeDetails;
22405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    changed_details->urls.swap(favicons_changed);
22415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BroadcastNotifications(chrome::NOTIFICATION_FAVICON_CHANGED,
22425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           changed_details);
22435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
22445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
22455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::UpdateFaviconMappingsAndFetchImpl(
22475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL* page_url,
22485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<GURL>& icon_urls,
22495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int icon_types,
22505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int desired_size_in_dip,
22512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<ui::ScaleFactor>& desired_scale_factors,
22522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::vector<FaviconBitmapResult>* bitmap_results) {
22535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If |page_url| is specified, |icon_types| must be either a single icon
22545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // type or icon types which are equivalent.
22555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!page_url ||
22565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         icon_types == FAVICON ||
22575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         icon_types == TOUCH_ICON ||
22585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         icon_types == TOUCH_PRECOMPOSED_ICON ||
22595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         icon_types == (TOUCH_ICON | TOUCH_PRECOMPOSED_ICON));
22602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bitmap_results->clear();
22615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2262b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!thumbnail_db_) {
22635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
22645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
22655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<FaviconID> favicon_ids;
22675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The icon type for which the mappings will the updated and data will be
22695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // returned.
22705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IconType selected_icon_type = INVALID_ICON;
22715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < icon_urls.size(); ++i) {
22735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& icon_url = icon_urls[i];
22745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IconType icon_type_out;
22755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const FaviconID favicon_id = thumbnail_db_->GetFaviconIDForFaviconURL(
22765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        icon_url, icon_types, &icon_type_out);
22775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (favicon_id) {
22795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Return and update icon mappings only for the largest icon type. As
22805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // |icon_urls| is not sorted in terms of icon type, clear |favicon_ids|
22815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // if an |icon_url| with a larger icon type is found.
22825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (icon_type_out > selected_icon_type) {
22835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        selected_icon_type = icon_type_out;
22845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        favicon_ids.clear();
22855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
22865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (icon_type_out == selected_icon_type)
22875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        favicon_ids.push_back(favicon_id);
22885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
22895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
22905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (page_url && !favicon_ids.empty()) {
22925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool mappings_updated =
22935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SetFaviconMappingsForPageAndRedirects(*page_url, selected_icon_type,
22945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              favicon_ids);
22955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (mappings_updated) {
22965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SendFaviconChangedNotificationForPageAndRedirects(*page_url);
22975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ScheduleCommit();
22985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
22995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
23005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetFaviconBitmapResultsForBestMatch(favicon_ids, desired_size_in_dip,
23022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      desired_scale_factors, bitmap_results);
23035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
23045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::SetFaviconBitmaps(
23065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FaviconID icon_id,
23072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<FaviconBitmapData>& favicon_bitmap_data,
23082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool* favicon_bitmaps_changed) {
23092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (favicon_bitmaps_changed)
23102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *favicon_bitmaps_changed = false;
23112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
23125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<FaviconBitmapIDSize> bitmap_id_sizes;
23135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_->GetFaviconBitmapIDSizes(icon_id, &bitmap_id_sizes);
23145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<FaviconBitmapData> to_add = favicon_bitmap_data;
23162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
23172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < bitmap_id_sizes.size(); ++i) {
23182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const gfx::Size& pixel_size = bitmap_id_sizes[i].pixel_size;
23192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::vector<FaviconBitmapData>::iterator match_it = to_add.end();
23202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (std::vector<FaviconBitmapData>::iterator it = to_add.begin();
23212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         it != to_add.end(); ++it) {
23222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (it->pixel_size == pixel_size) {
23232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        match_it = it;
23245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
23255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
23265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
23272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
23282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    FaviconBitmapID bitmap_id = bitmap_id_sizes[i].bitmap_id;
23292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (match_it == to_add.end()) {
23302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      thumbnail_db_->DeleteFaviconBitmap(bitmap_id);
23312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
23322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (favicon_bitmaps_changed)
23332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        *favicon_bitmaps_changed = true;
23345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
23352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (favicon_bitmaps_changed &&
23362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          !*favicon_bitmaps_changed &&
23372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          IsFaviconBitmapDataEqual(bitmap_id, match_it->bitmap_data)) {
23382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        thumbnail_db_->SetFaviconBitmapLastUpdateTime(
23392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            bitmap_id, base::Time::Now());
23402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      } else {
23412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        thumbnail_db_->SetFaviconBitmap(bitmap_id, match_it->bitmap_data,
23422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            base::Time::Now());
23432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
23442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (favicon_bitmaps_changed)
23452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          *favicon_bitmaps_changed = true;
23462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
23472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      to_add.erase(match_it);
23485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
23495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
23505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < to_add.size(); ++i) {
23522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    thumbnail_db_->AddFaviconBitmap(icon_id, to_add[i].bitmap_data,
23532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Time::Now(), to_add[i].pixel_size);
23545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (favicon_bitmaps_changed)
23562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      *favicon_bitmaps_changed = true;
23575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
23582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
23595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool HistoryBackend::ValidateSetFaviconsParams(
23612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<FaviconBitmapData>& favicon_bitmap_data) const {
23622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  typedef std::map<GURL, size_t> BitmapsPerIconURL;
23632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BitmapsPerIconURL num_bitmaps_per_icon_url;
23645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < favicon_bitmap_data.size(); ++i) {
2365b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (!favicon_bitmap_data[i].bitmap_data)
23665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
23675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GURL& icon_url = favicon_bitmap_data[i].icon_url;
23692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!num_bitmaps_per_icon_url.count(icon_url))
23702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      num_bitmaps_per_icon_url[icon_url] = 1u;
23712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else
23722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ++num_bitmaps_per_icon_url[icon_url];
23732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
23742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
23752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (num_bitmaps_per_icon_url.size() > kMaxFaviconsPerPage)
23762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
23775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (BitmapsPerIconURL::const_iterator it = num_bitmaps_per_icon_url.begin();
23792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       it != num_bitmaps_per_icon_url.end(); ++it) {
23802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (it->second > kMaxFaviconBitmapsPerIconURL)
23815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
23825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
23835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
23845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
23855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool HistoryBackend::IsFaviconBitmapDataEqual(
23872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    FaviconBitmapID bitmap_id,
23882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const scoped_refptr<base::RefCountedMemory>& new_bitmap_data) {
2389b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!new_bitmap_data)
23902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
23915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_refptr<base::RefCountedMemory> original_bitmap_data;
23932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  thumbnail_db_->GetFaviconBitmap(bitmap_id,
23942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                  NULL,
23952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                  &original_bitmap_data,
23962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                  NULL);
23972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return new_bitmap_data->Equals(original_bitmap_data);
23985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
23995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetFaviconsFromDB(
24015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
24025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int icon_types,
24035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int desired_size_in_dip,
24045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<ui::ScaleFactor>& desired_scale_factors,
24052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::vector<FaviconBitmapResult>* favicon_bitmap_results) {
24065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(favicon_bitmap_results);
24072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  favicon_bitmap_results->clear();
24085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2409b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_ || !thumbnail_db_)
24105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
24115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Time the query.
24135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TimeTicks beginning_time = TimeTicks::Now();
24145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get FaviconIDs for |page_url| and one of |icon_types|.
24165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<IconMapping> icon_mappings;
24175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_->GetIconMappingsForPageURL(page_url, icon_types,
24185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           &icon_mappings);
24195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<FaviconID> favicon_ids;
24205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < icon_mappings.size(); ++i)
24215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    favicon_ids.push_back(icon_mappings[i].icon_id);
24225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Populate |favicon_bitmap_results| and |icon_url_sizes|.
24242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool success = GetFaviconBitmapResultsForBestMatch(favicon_ids,
24252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      desired_size_in_dip, desired_scale_factors, favicon_bitmap_results);
24265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_TIMES("History.GetFavIconFromDB",  // historical name
24275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      TimeTicks::Now() - beginning_time);
24282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return success && !favicon_bitmap_results->empty();
24295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
24305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetFaviconBitmapResultsForBestMatch(
24325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<FaviconID>& candidate_favicon_ids,
24335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int desired_size_in_dip,
24345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<ui::ScaleFactor>& desired_scale_factors,
24352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::vector<FaviconBitmapResult>* favicon_bitmap_results) {
24365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  favicon_bitmap_results->clear();
24375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (candidate_favicon_ids.empty())
24395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
24405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Find the FaviconID and the FaviconBitmapIDs which best match
24425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |desired_size_in_dip| and |desired_scale_factors|.
24435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(pkotwicz): Select bitmap results from multiple favicons once
24445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // content::FaviconStatus supports multiple icon URLs.
24455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FaviconID best_favicon_id = 0;
24465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<FaviconBitmapID> best_bitmap_ids;
24475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  float highest_score = kSelectFaviconFramesInvalidScore;
24485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < candidate_favicon_ids.size(); ++i) {
24495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<FaviconBitmapIDSize> bitmap_id_sizes;
24505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_->GetFaviconBitmapIDSizes(candidate_favicon_ids[i],
24515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           &bitmap_id_sizes);
24525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Build vector of gfx::Size from |bitmap_id_sizes|.
24545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<gfx::Size> sizes;
24555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t j = 0; j < bitmap_id_sizes.size(); ++j)
24565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sizes.push_back(bitmap_id_sizes[j].pixel_size);
24575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<size_t> candidate_bitmap_indices;
24595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    float score = 0;
24605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SelectFaviconFrameIndices(sizes,
24615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              desired_scale_factors,
24625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              desired_size_in_dip,
24635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              &candidate_bitmap_indices,
24645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              &score);
24655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (score > highest_score) {
24665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      highest_score = score;
24675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      best_favicon_id = candidate_favicon_ids[i],
24685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      best_bitmap_ids.clear();
24695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (size_t j = 0; j < candidate_bitmap_indices.size(); ++j) {
24705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        size_t candidate_index = candidate_bitmap_indices[j];
24715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        best_bitmap_ids.push_back(
24725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            bitmap_id_sizes[candidate_index].bitmap_id);
24735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
24745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
24755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
24765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Construct FaviconBitmapResults from |best_favicon_id| and
24785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |best_bitmap_ids|.
24795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL icon_url;
24805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IconType icon_type;
24815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!thumbnail_db_->GetFaviconHeader(best_favicon_id, &icon_url,
24825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       &icon_type, NULL)) {
24835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
24845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
24855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < best_bitmap_ids.size(); ++i) {
24875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::Time last_updated;
24885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FaviconBitmapResult bitmap_result;
24895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bitmap_result.icon_url = icon_url;
24905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bitmap_result.icon_type = icon_type;
24915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!thumbnail_db_->GetFaviconBitmap(best_bitmap_ids[i],
24925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         &last_updated,
24935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         &bitmap_result.bitmap_data,
24945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         &bitmap_result.pixel_size)) {
24955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
24965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
24975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bitmap_result.expired = (Time::Now() - last_updated) >
24995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        TimeDelta::FromDays(kFaviconRefetchDays);
25005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (bitmap_result.is_valid())
25015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      favicon_bitmap_results->push_back(bitmap_result);
25025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
25035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
25045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
25055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::SetFaviconMappingsForPageAndRedirects(
25075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
25085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IconType icon_type,
25095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<FaviconID>& icon_ids) {
2510b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!thumbnail_db_)
25115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
25125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Find all the pages whose favicons we should set, we want to set it for
25145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // all the pages in the redirect chain if it redirected.
25155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  history::RedirectList redirects;
25165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetCachedRecentRedirects(page_url, &redirects);
25175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool mappings_changed = false;
25195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Save page <-> favicon associations.
25215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (history::RedirectList::const_iterator i(redirects.begin());
25225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != redirects.end(); ++i) {
25235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mappings_changed |= SetFaviconMappingsForPage(*i, icon_type, icon_ids);
25245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
25255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return mappings_changed;
25265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
25275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::SetFaviconMappingsForPage(
25295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
25305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IconType icon_type,
25315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<FaviconID>& icon_ids) {
25325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_LE(icon_ids.size(), kMaxFaviconsPerPage);
25335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool mappings_changed = false;
25345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Two icon types are considered 'equivalent' if one of the icon types is
25365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TOUCH_ICON and the other is TOUCH_PRECOMPOSED_ICON.
25375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
25385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Sets the icon mappings from |page_url| for |icon_type| to the favicons
25395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // with |icon_ids|. Mappings for |page_url| to favicons of type |icon_type|
25405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // whose FaviconID is not in |icon_ids| are removed. All icon mappings for
25415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |page_url| to favicons of a type equivalent to |icon_type| are removed.
25425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Remove any favicons which are orphaned as a result of the removal of the
25435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // icon mappings.
25445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<FaviconID> unmapped_icon_ids = icon_ids;
25465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<IconMapping> icon_mappings;
25485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_->GetIconMappingsForPageURL(page_url, &icon_mappings);
25495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<IconMapping>::iterator m = icon_mappings.begin();
25515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       m != icon_mappings.end(); ++m) {
25525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<FaviconID>::iterator icon_id_it = std::find(
25535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        unmapped_icon_ids.begin(), unmapped_icon_ids.end(), m->icon_id);
25545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If the icon mapping already exists, avoid removing it and adding it back.
25565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (icon_id_it != unmapped_icon_ids.end()) {
25575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      unmapped_icon_ids.erase(icon_id_it);
25585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
25595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
25605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if ((icon_type == TOUCH_ICON && m->icon_type == TOUCH_PRECOMPOSED_ICON) ||
25625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        (icon_type == TOUCH_PRECOMPOSED_ICON && m->icon_type == TOUCH_ICON) ||
25635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        (icon_type == m->icon_type)) {
25645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      thumbnail_db_->DeleteIconMapping(m->mapping_id);
25655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Removing the icon mapping may have orphaned the associated favicon so
25675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // we must recheck it. This is not super fast, but this case will get
25685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // triggered rarely, since normally a page will always map to the same
25695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // favicon IDs. It will mostly happen for favicons we import.
25705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!thumbnail_db_->HasMappingFor(m->icon_id))
25715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        thumbnail_db_->DeleteFavicon(m->icon_id);
25725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mappings_changed = true;
25735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
25745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
25755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < unmapped_icon_ids.size(); ++i) {
25775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_->AddIconMapping(page_url, unmapped_icon_ids[i]);
25785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mappings_changed = true;
25795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
25805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return mappings_changed;
25815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
25825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::GetCachedRecentRedirects(
25845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
25855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    history::RedirectList* redirect_list) {
25865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RedirectCache::iterator iter = recent_redirects_.Get(page_url);
25875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (iter != recent_redirects_.end()) {
25885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *redirect_list = iter->second;
25895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The redirect chain should have the destination URL as the last item.
25915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!redirect_list->empty());
25925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(redirect_list->back() == page_url);
25935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
25945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No known redirects, construct mock redirect chain containing |page_url|.
25955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    redirect_list->push_back(page_url);
25965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
25975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
25985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::SendFaviconChangedNotificationForPageAndRedirects(
26005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url) {
26015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  history::RedirectList redirect_list;
26025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetCachedRecentRedirects(page_url, &redirect_list);
26035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FaviconChangeDetails* changed_details = new FaviconChangeDetails;
26055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < redirect_list.size(); ++i)
26065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    changed_details->urls.insert(redirect_list[i]);
26075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BroadcastNotifications(chrome::NOTIFICATION_FAVICON_CHANGED,
26095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         changed_details);
26105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
26115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::Commit() {
2613b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
26145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
26155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note that a commit may not actually have been scheduled if a caller
26175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // explicitly calls this instead of using ScheduleCommit. Likewise, we
26185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // may reset the flag written by a pending commit. But this is OK! It
26195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // will merely cause extra commits (which is kind of the idea). We
26205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // could optimize more for this case (we may get two extra commits in
26215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // some cases) but it hasn't been important yet.
26225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CancelScheduledCommit();
26235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->CommitTransaction();
26255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(db_->transaction_nesting() == 0) << "Somebody left a transaction open";
26265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->BeginTransaction();
26275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2628b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (thumbnail_db_) {
26295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_->CommitTransaction();
26305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(thumbnail_db_->transaction_nesting() == 0) <<
26315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "Somebody left a transaction open";
26325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_->BeginTransaction();
26335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
26345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2635b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (archived_db_) {
26365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    archived_db_->CommitTransaction();
26375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    archived_db_->BeginTransaction();
26385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
26395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2640b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (text_database_) {
26415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    text_database_->CommitTransaction();
26425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    text_database_->BeginTransaction();
26435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
26445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
26455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::ScheduleCommit() {
2647b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (scheduled_commit_)
26485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
26495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scheduled_commit_ = new CommitLaterTask(this);
26505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MessageLoop::current()->PostDelayedTask(
26515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
26525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&CommitLaterTask::RunCommit, scheduled_commit_.get()),
26535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::TimeDelta::FromSeconds(kCommitIntervalSeconds));
26545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
26555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::CancelScheduledCommit() {
26575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (scheduled_commit_) {
26585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scheduled_commit_->Cancel();
26595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scheduled_commit_ = NULL;
26605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
26615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
26625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::ProcessDBTaskImpl() {
2664b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_) {
26655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // db went away, release all the refs.
26665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ReleaseDBTasks();
26675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
26685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
26695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Remove any canceled tasks.
26715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (!db_task_requests_.empty() && db_task_requests_.front()->canceled()) {
26725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_task_requests_.front()->Release();
26735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_task_requests_.pop_front();
26745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
26755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (db_task_requests_.empty())
26765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
26775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Run the first task.
26795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HistoryDBTaskRequest* request = db_task_requests_.front();
26805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_task_requests_.pop_front();
26815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->value->RunOnDBThread(this, db_.get())) {
26825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The task is done. Notify the callback.
26835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    request->ForwardResult();
26845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We AddRef'd the request before adding, need to release it now.
26855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    request->Release();
26865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
26875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Tasks wants to run some more. Schedule it at the end of current tasks.
26885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_task_requests_.push_back(request);
26895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // And process it after an invoke later.
26905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MessageLoop::current()->PostTask(
26915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE, base::Bind(&HistoryBackend::ProcessDBTaskImpl, this));
26925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
26935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
26945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::ReleaseDBTasks() {
26965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::list<HistoryDBTaskRequest*>::iterator i =
26975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       db_task_requests_.begin(); i != db_task_requests_.end(); ++i) {
26985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (*i)->Release();
26995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
27005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_task_requests_.clear();
27015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
27025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
27045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
27055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Generic operations
27065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
27075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
27085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::DeleteURLs(const std::vector<GURL>& urls) {
27105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expirer_.DeleteURLs(urls);
27115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->GetStartDate(&first_recorded_time_);
27135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Force a commit, if the user is deleting something for privacy reasons, we
27145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // want to get it on disk ASAP.
27155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Commit();
27165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
27175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::DeleteURL(const GURL& url) {
27195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expirer_.DeleteURL(url);
27205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->GetStartDate(&first_recorded_time_);
27225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Force a commit, if the user is deleting something for privacy reasons, we
27235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // want to get it on disk ASAP.
27245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Commit();
27255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
27265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::ExpireHistoryBetween(
27285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::set<GURL>& restrict_urls,
27295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Time begin_time,
27305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Time end_time) {
2731b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
27322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (begin_time.is_null() && (end_time.is_null() || end_time.is_max()) &&
27332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        restrict_urls.empty()) {
27345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Special case deleting all history so it can be faster and to reduce the
27355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // possibility of an information leak.
27365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DeleteAllHistory();
27375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
27385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Clearing parts of history, have the expirer do the depend
27395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      expirer_.ExpireHistoryBetween(restrict_urls, begin_time, end_time);
27405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Force a commit, if the user is deleting something for privacy reasons,
27425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // we want to get it on disk ASAP.
27435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Commit();
27445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
27455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
27465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (begin_time <= first_recorded_time_)
27485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_->GetStartDate(&first_recorded_time_);
27492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
27502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
27512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::ExpireHistoryForTimes(
27522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::set<base::Time>& times,
27532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::Time begin_time, base::Time end_time) {
2754b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (times.empty() || !db_)
27552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
27562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
27572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(*times.begin() >= begin_time)
27582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      << "Min time is before begin time: "
27592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      << times.begin()->ToJsTime() << " v.s. " << begin_time.ToJsTime();
27602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(*times.rbegin() < end_time)
27612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      << "Max time is after end time: "
27622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      << times.rbegin()->ToJsTime() << " v.s. " << end_time.ToJsTime();
27632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
27642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  history::QueryOptions options;
27652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  options.begin_time = begin_time;
27662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  options.end_time = end_time;
27672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  options.duplicate_policy = QueryOptions::KEEP_ALL_DUPLICATES;
27682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  QueryResults results;
27692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  QueryHistoryBasic(db_.get(), db_.get(), options, &results);
27702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
27712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // 1st pass: find URLs that are visited at one of |times|.
27722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::set<GURL> urls;
27732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < results.size(); ++i) {
27742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (times.count(results[i].visit_time()) > 0)
27752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      urls.insert(results[i].url());
27762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
27772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (urls.empty())
27782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
27792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
27802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // 2nd pass: collect all visit times of those URLs.
27812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<base::Time> times_to_expire;
27822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < results.size(); ++i) {
27832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (urls.count(results[i].url()))
27842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      times_to_expire.push_back(results[i].visit_time());
27852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
27862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
27872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Put the times in reverse chronological order and remove
27882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // duplicates (for expirer_.ExpireHistoryForTimes()).
27892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::sort(times_to_expire.begin(), times_to_expire.end(),
27902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            std::greater<base::Time>());
27912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  times_to_expire.erase(
27922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      std::unique(times_to_expire.begin(), times_to_expire.end()),
27932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      times_to_expire.end());
27942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
27952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Expires by times and commit.
27962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!times_to_expire.empty());
27972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  expirer_.ExpireHistoryForTimes(times_to_expire);
27982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Commit();
27992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
28002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(times_to_expire.back() >= first_recorded_time_);
28012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Update |first_recorded_time_| if we expired it.
28022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (times_to_expire.back() == first_recorded_time_)
28032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    db_->GetStartDate(&first_recorded_time_);
28042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
28055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::ExpireHistory(
28072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<history::ExpireHistoryArgs>& expire_list) {
2808b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
28092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool update_first_recorded_time = false;
28102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
28112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (std::vector<history::ExpireHistoryArgs>::const_iterator it =
28122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         expire_list.begin(); it != expire_list.end(); ++it) {
28132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      expirer_.ExpireHistoryBetween(it->urls, it->begin_time, it->end_time);
28145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (it->begin_time < first_recorded_time_)
28162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        update_first_recorded_time = true;
28172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
28182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Commit();
28192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
28202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Update |first_recorded_time_| if any deletion might have affected it.
28212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (update_first_recorded_time)
28222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      db_->GetStartDate(&first_recorded_time_);
28232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
28245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
28255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::URLsNoLongerBookmarked(const std::set<GURL>& urls) {
2827b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
28285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
28295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::set<GURL>::const_iterator i = urls.begin(); i != urls.end(); ++i) {
28315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLRow url_row;
28325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!db_->GetRowForURL(*i, &url_row))
28335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;  // The URL isn't in the db; nothing to do.
28345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitVector visits;
28365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_->GetVisitsForURL(url_row.id(), &visits);
28375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (visits.empty())
28395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      expirer_.DeleteURL(*i);  // There are no more visits; nuke the URL.
28405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
28415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
28425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::KillHistoryDatabase() {
2844b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
28455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
28465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Rollback transaction because Raze() cannot be called from within a
28485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // transaction.
28495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->RollbackTransaction();
28505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool success = db_->Raze();
28515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_BOOLEAN("History.KillHistoryDatabaseResult", success);
28525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
28545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Release AndroidProviderBackend before other objects.
28555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  android_provider_backend_.reset();
28565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
28575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The expirer keeps tabs on the active databases. Tell it about the
28595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // databases which will be closed.
28605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expirer_.SetDatabases(NULL, NULL, NULL, NULL);
28615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Reopen a new transaction for |db_| for the sake of CloseAllDatabases().
28635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->BeginTransaction();
28645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CloseAllDatabases();
28655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
28665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::ProcessDBTask(
28685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<HistoryDBTaskRequest> request) {
2869b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  DCHECK(request);
28705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
28715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
28725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool task_scheduled = !db_task_requests_.empty();
28745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make sure we up the refcount of the request. ProcessDBTaskImpl will
28755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // release when done with the task.
28765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->AddRef();
28775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_task_requests_.push_back(request.get());
28785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!task_scheduled) {
28795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No other tasks are scheduled. Process request now.
28805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ProcessDBTaskImpl();
28815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
28825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
28835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::BroadcastNotifications(
28855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int type,
28865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HistoryDetails* details_deleted) {
28875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |delegate_| may be NULL if |this| is in the process of closing (closed by
2888b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // HistoryService -> HistoryBackend::Closing().
2889b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (delegate_)
28905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delegate_->BroadcastNotifications(type, details_deleted);
28915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
28925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delete details_deleted;
28935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
28945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2895b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void HistoryBackend::NotifySyncURLsDeleted(bool all_history,
2896b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                           bool archived,
2897b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                           URLRows* rows) {
2898b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (typed_url_syncable_service_.get())
2899b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    typed_url_syncable_service_->OnUrlsDeleted(all_history, archived, rows);
2900b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
2901b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
29025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Deleting --------------------------------------------------------------------
29035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::DeleteAllHistory() {
29055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Our approach to deleting all history is:
29065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //  1. Copy the bookmarks and their dependencies to new tables with temporary
29075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //     names.
29085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //  2. Delete the original tables. Since tables can not share pages, we know
29095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //     that any data we don't want to keep is now in an unused page.
29105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //  3. Renaming the temporary tables to match the original.
29115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //  4. Vacuuming the database to delete the unused pages.
29125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
29135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Since we are likely to have very few bookmarks and their dependencies
29145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // compared to all history, this is also much faster than just deleting from
29155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the original tables directly.
29165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the bookmarked URLs.
29185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<BookmarkService::URLAndTitle> starred_urls;
29195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BookmarkService* bookmark_service = GetBookmarkService();
29205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (bookmark_service)
29215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bookmark_service_->GetBookmarks(&starred_urls);
29225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLRows kept_urls;
29245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < starred_urls.size(); i++) {
29255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLRow row;
29265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!db_->GetRowForURL(starred_urls[i].url, &row))
29275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
29285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Clear the last visit time so when we write these rows they are "clean."
29305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    row.set_last_visit(Time());
29315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    row.set_visit_count(0);
29325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    row.set_typed_count(0);
29335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kept_urls.push_back(row);
29345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
29355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Clear thumbnail and favicon history. The favicons for the given URLs will
29375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // be kept.
29385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ClearAllThumbnailHistory(&kept_urls)) {
29395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Thumbnail history could not be cleared";
29405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We continue in this error case. If the user wants to delete their
29415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // history, we should delete as much as we can.
29425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
29435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ClearAllMainHistory will change the IDs of the URLs in kept_urls. Therfore,
29455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // we clear the list afterwards to make sure nobody uses this invalid data.
29465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ClearAllMainHistory(kept_urls))
29475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Main history could not be cleared";
29485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kept_urls.clear();
29495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Delete FTS files & archived history.
2951b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (text_database_) {
29525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We assume that the text database has one transaction on them that we need
29535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // to close & restart (the long-running history transaction).
29545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    text_database_->CommitTransaction();
29555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    text_database_->DeleteAll();
29565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    text_database_->BeginTransaction();
29575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
29585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2959b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (archived_db_) {
29605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Close the database and delete the file.
29615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    archived_db_.reset();
29622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::FilePath archived_file_name = GetArchivedFileName();
29635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    file_util::Delete(archived_file_name, false);
29645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Now re-initialize the database (which may fail).
29665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    archived_db_.reset(new ArchivedDatabase());
29675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!archived_db_->Init(archived_file_name)) {
29685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(WARNING) << "Could not initialize the archived database.";
29695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      archived_db_.reset();
29705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
29715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Open our long-running transaction on this database.
29725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      archived_db_->BeginTransaction();
29735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
29745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
29755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->GetStartDate(&first_recorded_time_);
29775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Send out the notfication that history is cleared. The in-memory datdabase
29795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // will pick this up and clear itself.
29805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLsDeletedDetails* details = new URLsDeletedDetails;
29815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  details->all_history = true;
2982b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  NotifySyncURLsDeleted(true, false, NULL);
29835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URLS_DELETED, details);
29845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
29855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::ClearAllThumbnailHistory(URLRows* kept_urls) {
2987b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!thumbnail_db_) {
29885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // When we have no reference to the thumbnail database, maybe there was an
29895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // error opening it. In this case, we just try to blow it away to try to
29905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // fix the error if it exists. This may fail, in which case either the
29915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // file doesn't exist or there's no more we can do.
29925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    file_util::Delete(GetThumbnailFileName(), false);
29935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
29945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
29955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create duplicate icon_mapping, favicon, and favicon_bitmaps tables, this
29975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // is where the favicons we want to keep will be stored.
29985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!thumbnail_db_->InitTemporaryTables())
29995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
30005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
30015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This maps existing favicon IDs to the ones in the temporary table.
30025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef std::map<FaviconID, FaviconID> FaviconMap;
30035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FaviconMap copied_favicons;
30045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
30055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Copy all unique favicons to the temporary table, and update all the
30065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // URLs to have the new IDs.
30075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (URLRows::iterator i = kept_urls->begin(); i != kept_urls->end(); ++i) {
30085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<IconMapping> icon_mappings;
30095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!thumbnail_db_->GetIconMappingsForPageURL(i->url(), &icon_mappings))
30105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
30115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
30125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (std::vector<IconMapping>::iterator m = icon_mappings.begin();
30135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         m != icon_mappings.end(); ++m) {
30145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FaviconID old_id = m->icon_id;
30155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FaviconID new_id;
30165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FaviconMap::const_iterator found = copied_favicons.find(old_id);
30175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (found == copied_favicons.end()) {
30185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        new_id = thumbnail_db_->CopyFaviconAndFaviconBitmapsToTemporaryTables(
30195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            old_id);
30205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        copied_favicons[old_id] = new_id;
30215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
30225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // We already encountered a URL that used this favicon, use the ID we
30235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // previously got.
30245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        new_id = found->second;
30255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
30265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Add Icon mapping, and we don't care wheteher it suceeded or not.
30275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      thumbnail_db_->AddToTemporaryIconMappingTable(i->url(), new_id);
30285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
30295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
30305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
30315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO (michaelbai): Add the unit test once AndroidProviderBackend is
30325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // avaliable in HistoryBackend.
30335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->ClearAndroidURLRows();
30345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
30355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
30365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Drop original favicon_bitmaps, favicons, and icon mapping tables and
30375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // replace them with the duplicate tables. Recreate the other tables. This
30385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // will make the database consistent again.
30395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_->CommitTemporaryTables();
30405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
30415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_->RecreateThumbnailTable();
30425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
30435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Vacuum to remove all the pages associated with the dropped tables. There
30445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // must be no transaction open on the table when we do this. We assume that
30455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // our long-running transaction is open, so we complete it and start it again.
30465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(thumbnail_db_->transaction_nesting() == 1);
30475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_->CommitTransaction();
30485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_->Vacuum();
30495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_->BeginTransaction();
30505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
30515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
30525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
30535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::ClearAllMainHistory(const URLRows& kept_urls) {
30545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create the duplicate URL table. We will copy the kept URLs into this.
30555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->CreateTemporaryURLTable())
30565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
30575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
30585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Insert the URLs into the temporary table, we need to keep a map of changed
30595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // IDs since the ID will be different in the new table.
30605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef std::map<URLID, URLID> URLIDMap;
30615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLIDMap old_to_new;  // Maps original ID to new one.
30625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (URLRows::const_iterator i = kept_urls.begin(); i != kept_urls.end();
30635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ++i) {
30645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLID new_id = db_->AddTemporaryURL(*i);
30655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    old_to_new[i->id()] = new_id;
30665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
30675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
30685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Replace the original URL table with the temporary one.
30695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->CommitTemporaryURLTable())
30705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
30715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
30725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Delete the old tables and recreate them empty.
30735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->RecreateAllTablesButURL();
30745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
30755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Vacuum to reclaim the space from the dropped tables. This must be done
30765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // when there is no transaction open, and we assume that our long-running
30775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // transaction is currently open.
30785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->CommitTransaction();
30795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->Vacuum();
30805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->BeginTransaction();
30815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->GetStartDate(&first_recorded_time_);
30825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
30835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
30845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
30855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
30865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BookmarkService* HistoryBackend::GetBookmarkService() {
30875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (bookmark_service_)
30885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bookmark_service_->BlockTillLoaded();
30895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return bookmark_service_;
30905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
30915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
30925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::NotifyVisitObservers(const VisitRow& visit) {
30935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BriefVisitInfo info;
30945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  info.url_id = visit.url_id;
30955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  info.time = visit.visit_time;
30965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  info.transition = visit.transition;
30975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we don't have a delegate yet during setup or shutdown, we will drop
30985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // these notifications.
3099b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (delegate_)
31005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delegate_->NotifyVisitDBObserversOnAddVisit(info);
31015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
31025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
31035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace history
3104