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"
17bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch#include "base/files/file_enumerator.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_vector.h"
209ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/histogram.h"
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/rand_util.h"
23868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
24868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
25eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h"
267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/chrome_notification_types.h"
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/history/download_row.h"
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/history/history_db_task.h"
295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "chrome/browser/history/history_db_task.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/history_notifications.h"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/in_memory_history_backend.h"
325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "chrome/browser/history/in_memory_history_backend.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/top_sites.h"
34b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "chrome/browser/history/typed_url_syncable_service.h"
355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "chrome/browser/history/typed_url_syncable_service.h"
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/visit_filter.h"
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_constants.h"
38eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/common/importer/imported_favicon_usage.h"
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/url_constants.h"
405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "components/favicon_base/select_favicon_frames.h"
4146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "components/history/core/browser/history_client.h"
42116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "components/history/core/browser/keyword_search_term.h"
436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "components/history/core/browser/page_usage_data.h"
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sql/error_delegate_util.h"
461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "third_party/skia/include/core/SkBitmap.h"
471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "ui/gfx/codec/png_codec.h"
48eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "url/gurl.h"
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/android/android_provider_backend.h"
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::Time;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::TimeDelta;
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::TimeTicks;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)/* The HistoryBackend consists of two components:
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HistoryDatabase (stores past 3 months of history)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      URLDatabase (stores a list of URLs)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DownloadDatabase (stores a list of downloads)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VisitDatabase (stores a list of visits for the URLs)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VisitSegmentDatabase (stores groups of URLs for the most visited view).
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    ExpireHistoryBackend (manages deleting things older than 3 months)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace history {
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
71116680a4aac90f2aa7413d9095a592090648e557Ben Murdochnamespace {
72116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid RunUnlessCanceled(
73116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const base::Closure& closure,
74116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const base::CancelableTaskTracker::IsCanceledCallback& is_canceled) {
75116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!is_canceled.Run())
76116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    closure.Run();
77116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
78116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}  // namespace
79116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
80116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#if defined(OS_ANDROID)
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.
8568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const int kSegmentDataRetention = 90;
86116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#endif
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// How long we'll wait to do a commit, so that things are batched together.
8968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const int kCommitIntervalSeconds = 10;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The amount of time before we re-fetch the favicon.
9268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const int kFaviconRefetchDays = 7;
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The maximum number of items we'll allow in the redirect list before
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// deleting some.
9668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const int kMaxRedirectCount = 32;
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The number of days old a history entry can be before it is considered "old"
9946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// and is deleted.
10046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)const int kExpireDaysThreshold = 90;
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
102eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#if defined(OS_ANDROID)
103eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// The maximum number of top sites to track when recording top page visit stats.
10468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const size_t kPageVisitStatsMaxTopSites = 50;
105eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif
106eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Converts from PageUsageData to MostVisitedURL. |redirects| is a
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// list of redirects for this URL. Empty list means no redirects.
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MostVisitedURL MakeMostVisitedURL(const PageUsageData& page_data,
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  const RedirectList& redirects) {
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MostVisitedURL mv;
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mv.url = page_data.GetURL();
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mv.title = page_data.GetTitle();
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (redirects.empty()) {
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Redirects must contain at least the target url.
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mv.redirects.push_back(mv.url);
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mv.redirects = redirects;
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (mv.redirects[mv.redirects.size() - 1] != mv.url) {
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // The last url must be the target url.
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mv.redirects.push_back(mv.url);
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return mv;
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This task is run on a timer so that commits happen at regular intervals
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// so they are batched together. The important thing about this class is that
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// it supports canceling of the task so the reference to the backend will be
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// freed. The problem is that when history is shutting down, there is likely
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to be one of these commits still pending and holding a reference.
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The backend can call Cancel to have this task release the reference. The
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// task will still run (if we ever get to processing the event before
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// shutdown), but it will not do anything.
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Note that this is a refcounted object and is not a task in itself. It should
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// be assigned to a RunnableMethod.
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(brettw): bug 1165182: This should be replaced with a
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// base::WeakPtrFactory which will handle everything automatically (like we do
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// in ExpireHistoryBackend).
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class CommitLaterTask : public base::RefCounted<CommitLaterTask> {
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit CommitLaterTask(HistoryBackend* history_backend)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : history_backend_(history_backend) {
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The backend will call this function if it is being destroyed so that we
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // release our reference.
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Cancel() {
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    history_backend_ = NULL;
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void RunCommit() {
156868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (history_backend_.get())
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      history_backend_->Commit();
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  friend class base::RefCounted<CommitLaterTask>;
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~CommitLaterTask() {}
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<HistoryBackend> history_backend_;
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
168f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
169116680a4aac90f2aa7413d9095a592090648e557Ben MurdochQueuedHistoryDBTask::QueuedHistoryDBTask(
1705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    scoped_ptr<HistoryDBTask> task,
171116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    scoped_refptr<base::SingleThreadTaskRunner> origin_loop,
172116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const base::CancelableTaskTracker::IsCanceledCallback& is_canceled)
1735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    : task_(task.Pass()), origin_loop_(origin_loop), is_canceled_(is_canceled) {
174116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(task_);
1751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(origin_loop_.get());
176116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(!is_canceled_.is_null());
177f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
178f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
179116680a4aac90f2aa7413d9095a592090648e557Ben MurdochQueuedHistoryDBTask::~QueuedHistoryDBTask() {
1805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Ensure that |task_| is destroyed on its origin thread.
1815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  origin_loop_->PostTask(
1825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      FROM_HERE,
1835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      base::Bind(&base::DeletePointer<HistoryDBTask>,
1845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                 base::Unretained(task_.release())));
185116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
186116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
187116680a4aac90f2aa7413d9095a592090648e557Ben Murdochbool QueuedHistoryDBTask::is_canceled() {
188116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return is_canceled_.Run();
189116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
190116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
1915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool QueuedHistoryDBTask::Run(HistoryBackend* backend,
192116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                        HistoryDatabase* db) {
193116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return task_->RunOnDBThread(backend, db);
194116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
195116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
1965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void QueuedHistoryDBTask::DoneRun() {
197116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  origin_loop_->PostTask(
198116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      FROM_HERE,
199116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      base::Bind(&RunUnlessCanceled,
2005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                 base::Bind(&HistoryDBTask::DoneRunOnMainThread,
2015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                            base::Unretained(task_.get())),
202116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                 is_canceled_));
203f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
204f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// HistoryBackend --------------------------------------------------------------
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HistoryBackend::HistoryBackend(const base::FilePath& history_dir,
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               Delegate* delegate,
20946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                               HistoryClient* history_client)
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : delegate_(delegate),
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      history_dir_(history_dir),
2127d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      scheduled_kill_db_(false),
21346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      expirer_(this, history_client),
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      recent_redirects_(kMaxRedirectCount),
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      backend_destroy_message_loop_(NULL),
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      segment_queried_(false),
21746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      history_client_(history_client) {
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HistoryBackend::~HistoryBackend() {
221868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(!scheduled_commit_.get()) << "Deleting without cleanup";
2225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  STLDeleteContainerPointers(queued_history_db_tasks_.begin(),
2235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                             queued_history_db_tasks_.end());
224116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  queued_history_db_tasks_.clear();
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Release AndroidProviderBackend before other objects.
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  android_provider_backend_.reset();
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // First close the databases before optionally running the "destroy" task.
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CloseAllDatabases();
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!backend_destroy_task_.is_null()) {
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Notify an interested party (typically a unit test) that we're done.
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(backend_destroy_message_loop_);
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    backend_destroy_message_loop_->PostTask(FROM_HERE, backend_destroy_task_);
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
241eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  sql::Connection::Delete(GetAndroidCacheFileName());
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::Init(const std::string& languages, bool force_fail) {
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!force_fail)
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    InitImpl(languages);
248a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  delegate_->DBLoaded();
249b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  typed_url_syncable_service_.reset(new TypedUrlSyncableService(this));
250ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  memory_pressure_listener_.reset(new base::MemoryPressureListener(
251ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      base::Bind(&HistoryBackend::OnMemoryPressure, base::Unretained(this))));
252eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#if defined(OS_ANDROID)
253eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  PopulateMostVisitedURLMap();
254eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void HistoryBackend::SetOnBackendDestroyTask(base::MessageLoop* message_loop,
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             const base::Closure& task) {
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!backend_destroy_task_.is_null())
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(WARNING) << "Setting more than one destroy task, overriding";
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  backend_destroy_message_loop_ = message_loop;
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  backend_destroy_task_ = task;
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::Closing() {
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Any scheduled commit will have a reference to us, we must make it
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // release that reference before we can be destroyed.
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CancelScheduledCommit();
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Release our reference to the delegate, this reference will be keeping the
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // history service alive.
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delegate_.reset();
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void HistoryBackend::ClearCachedDataForContextID(ContextID context_id) {
276f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  tracker_.ClearCachedDataForContextID(context_id);
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath HistoryBackend::GetThumbnailFileName() const {
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return history_dir_.Append(chrome::kThumbnailsFilename);
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath HistoryBackend::GetFaviconsFileName() const {
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return history_dir_.Append(chrome::kFaviconsFilename);
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath HistoryBackend::GetArchivedFileName() const {
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return history_dir_.Append(chrome::kArchivedHistoryFilename);
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath HistoryBackend::GetAndroidCacheFileName() const {
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return history_dir_.Append(chrome::kAndroidCacheFilename);
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SegmentID HistoryBackend::GetLastSegmentID(VisitID from_visit) {
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set is used to detect referrer loops.  Should not happen, but can
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // if the database is corrupt.
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::set<VisitID> visit_set;
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitID visit_id = from_visit;
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (visit_id) {
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitRow row;
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!db_->GetRowForVisit(visit_id, &row))
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 0;
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (row.segment_id)
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return row.segment_id;  // Found a visit in this change with a segment.
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Check the referrer of this visit, if any.
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    visit_id = row.referring_visit;
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (visit_set.find(visit_id) != visit_set.end()) {
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED() << "Loop in referer chain, giving up";
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    visit_set.insert(visit_id);
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0;
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SegmentID HistoryBackend::UpdateSegments(
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url,
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitID from_visit,
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitID visit_id,
3251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    ui::PageTransition transition_type,
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Time ts) {
327b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We only consider main frames.
3311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!ui::PageTransitionIsMainFrame(transition_type))
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SegmentID segment_id = 0;
3351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ui::PageTransition t =
3361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      ui::PageTransitionStripQualifier(transition_type);
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Are we at the beginning of a new segment?
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note that navigating to an existing entry (with back/forward) reuses the
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // same transition type.  We are not adding it as a new segment in that case
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // because if this was the target of a redirect, we might end up with
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 2 entries for the same final URL. Ex: User types google.net, gets
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // redirected to google.com. A segment is created for google.net. On
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // google.com users navigates through a link, then press back. That last
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // navigation is for the entry google.com transition typed. We end up adding
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // a segment for that one as well. So we end up with google.net and google.com
34758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // in the segment table, showing as 2 entries in the NTP.
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note also that we should still be updating the visit count for that segment
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // which we are not doing now. It should be addressed when
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // http://crbug.com/96860 is fixed.
3511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if ((t == ui::PAGE_TRANSITION_TYPED ||
3521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci       t == ui::PAGE_TRANSITION_AUTO_BOOKMARK) &&
3531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      (transition_type & ui::PAGE_TRANSITION_FORWARD_BACK) == 0) {
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If so, create or get the segment.
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string segment_name = db_->ComputeSegmentName(url);
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLID url_id = db_->GetRowForURL(url, NULL);
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!url_id)
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 0;
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
360116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    segment_id = db_->GetSegmentNamed(segment_name);
361116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (!segment_id) {
362116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      segment_id = db_->CreateSegment(url_id, segment_name);
363116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      if (!segment_id) {
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NOTREACHED();
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return 0;
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Note: if we update an existing segment, we update the url used to
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // represent that segment in order to minimize stale most visited
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // images.
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_->UpdateSegmentRepresentationURL(segment_id, url_id);
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Note: it is possible there is no segment ID set for this visit chain.
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This can happen if the initial navigation wasn't AUTO_BOOKMARK or
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TYPED. (For example GENERATED). In this case this visit doesn't count
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // toward any segment.
378116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    segment_id = GetLastSegmentID(from_visit);
379116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (!segment_id)
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 0;
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set the segment in the visit.
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->SetSegmentID(visit_id, segment_id)) {
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Finally, increase the counter for that segment / day.
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->IncreaseSegmentVisitCount(segment_id, ts, 1)) {
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return segment_id;
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
397f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void HistoryBackend::UpdateWithPageEndTime(ContextID context_id,
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           int32 page_id,
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           const GURL& url,
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           Time end_ts) {
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Will be filled with the URL ID and the visit ID of the last addition.
402f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  VisitID visit_id = tracker_.GetLastVisit(context_id, page_id, url);
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateVisitDuration(visit_id, end_ts);
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::UpdateVisitDuration(VisitID visit_id, const Time end_ts) {
407b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the starting visit_time for visit_id.
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitRow visit_row;
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (db_->GetRowForVisit(visit_id, &visit_row)) {
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We should never have a negative duration time even when time is skewed.
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    visit_row.visit_duration = end_ts > visit_row.visit_time ?
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        end_ts - visit_row.visit_time : TimeDelta::FromMicroseconds(0);
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_->UpdateVisitRow(visit_row);
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::AddPage(const HistoryAddPageArgs& request) {
421b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Will be filled with the URL ID and the visit ID of the last addition.
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::pair<URLID, VisitID> last_ids(0, tracker_.GetLastVisit(
426f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      request.context_id, request.page_id, request.referrer));
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitID from_visit_id = last_ids.second;
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If a redirect chain is given, we expect the last item in that chain to be
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the final URL.
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(request.redirects.empty() ||
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         request.redirects.back() == request.url);
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the user is adding older history, we need to make sure our times
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // are correct.
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request.time < first_recorded_time_)
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    first_recorded_time_ = request.time;
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ui::PageTransition request_transition = request.transition;
4411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ui::PageTransition stripped_transition =
4421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    ui::PageTransitionStripQualifier(request_transition);
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool is_keyword_generated =
4441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      (stripped_transition == ui::PAGE_TRANSITION_KEYWORD_GENERATED);
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the user is navigating to a not-previously-typed intranet hostname,
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // change the transition to TYPED so that the omnibox will learn that this is
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // a known host.
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool has_redirects = request.redirects.size() > 1;
4501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (ui::PageTransitionIsMainFrame(request_transition) &&
4511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      (stripped_transition != ui::PAGE_TRANSITION_TYPED) &&
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !is_keyword_generated) {
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& origin_url(has_redirects ?
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        request.redirects[0] : request.url);
455010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    if (origin_url.SchemeIs(url::kHttpScheme) ||
456010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        origin_url.SchemeIs(url::kHttpsScheme) ||
457cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        origin_url.SchemeIs(url::kFtpScheme)) {
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::string host(origin_url.host());
459a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      size_t registry_length =
460a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)          net::registry_controlled_domains::GetRegistryLength(
461a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)              host,
462a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)              net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES,
463a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)              net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
464a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      if (registry_length == 0 && !db_->IsTypedHost(host)) {
4651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        stripped_transition = ui::PAGE_TRANSITION_TYPED;
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        request_transition =
4671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            ui::PageTransitionFromInt(
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                stripped_transition |
4691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                ui::PageTransitionGetQualifier(request_transition));
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!has_redirects) {
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The single entry is both a chain start and end.
4761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    ui::PageTransition t = ui::PageTransitionFromInt(
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        request_transition |
4781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        ui::PAGE_TRANSITION_CHAIN_START |
4791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        ui::PAGE_TRANSITION_CHAIN_END);
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No redirect case (one element means just the page itself).
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    last_ids = AddPageVisit(request.url, request.time,
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            last_ids.second, t, request.visit_source);
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Update the segment for this visit. KEYWORD_GENERATED visits should not
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // result in changing most visited, so we don't update segments (most
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // visited db).
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!is_keyword_generated) {
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      UpdateSegments(request.url, from_visit_id, last_ids.second, t,
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     request.time);
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Update the referrer's duration.
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      UpdateVisitDuration(from_visit_id, request.time);
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Redirect case. Add the redirect chain.
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    ui::PageTransition redirect_info =
4991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        ui::PAGE_TRANSITION_CHAIN_START;
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RedirectList redirects = request.redirects;
502f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (redirects[0].SchemeIs(url::kAboutScheme)) {
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // When the redirect source + referrer is "about" we skip it. This
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // happens when a page opens a new frame/window to about:blank and then
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // script sets the URL to somewhere else (used to hide the referrer). It
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // would be nice to keep all these redirects properly but we don't ever
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // see the initial about:blank load, so we don't know where the
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // subsequent client redirect came from.
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      //
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // In this case, we just don't bother hooking up the source of the
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // redirects, so we remove it.
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      redirects.erase(redirects.begin());
5131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    } else if (request_transition & ui::PAGE_TRANSITION_CLIENT_REDIRECT) {
5141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      redirect_info = ui::PAGE_TRANSITION_CLIENT_REDIRECT;
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // The first entry in the redirect chain initiated a client redirect.
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We don't add this to the database since the referrer is already
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // there, so we skip over it but change the transition type of the first
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // transition to client redirect.
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      //
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // The referrer is invalid when restoring a session that features an
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // https tab that redirects to a different host or to http. In this
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // case we don't need to reconnect the new redirect with the existing
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // chain.
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (request.referrer.is_valid()) {
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        DCHECK(request.referrer == redirects[0]);
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        redirects.erase(redirects.begin());
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // If the navigation entry for this visit has replaced that for the
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // first visit, remove the CHAIN_END marker from the first visit. This
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // can be called a lot, for example, the page cycler, and most of the
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // time we won't have changed anything.
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        VisitRow visit_row;
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (request.did_replace_entry &&
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            db_->GetRowForVisit(last_ids.second, &visit_row) &&
5351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            visit_row.transition & ui::PAGE_TRANSITION_CHAIN_END) {
5361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          visit_row.transition = ui::PageTransitionFromInt(
5371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci              visit_row.transition & ~ui::PAGE_TRANSITION_CHAIN_END);
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          db_->UpdateVisitRow(visit_row);
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t redirect_index = 0; redirect_index < redirects.size();
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         redirect_index++) {
5451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      ui::PageTransition t =
5461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          ui::PageTransitionFromInt(stripped_transition | redirect_info);
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // If this is the last transition, add a CHAIN_END marker
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (redirect_index == (redirects.size() - 1)) {
5501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        t = ui::PageTransitionFromInt(
5511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            t | ui::PAGE_TRANSITION_CHAIN_END);
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Record all redirect visits with the same timestamp. We don't display
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // them anyway, and if we ever decide to, we can reconstruct their order
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // from the redirect chain.
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      last_ids = AddPageVisit(redirects[redirect_index],
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              request.time, last_ids.second,
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              t, request.visit_source);
5601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      if (t & ui::PAGE_TRANSITION_CHAIN_START) {
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Update the segment for this visit.
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        UpdateSegments(redirects[redirect_index],
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       from_visit_id, last_ids.second, t, request.time);
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Update the visit_details for this visit.
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        UpdateVisitDuration(from_visit_id, request.time);
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Subsequent transitions in the redirect list must all be server
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // redirects.
5711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      redirect_info = ui::PAGE_TRANSITION_SERVER_REDIRECT;
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Last, save this redirect chain for later so we can set titles & favicons
575bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    // on the redirected pages properly.
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    recent_redirects_.Put(request.url, redirects);
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(brettw) bug 1140015: Add an "add page" notification so the history
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // views can keep in sync.
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Add the last visit to the tracker so we can get outgoing transitions.
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(evanm): Due to http://b/1194536 we lose the referrers of a subframe
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // navigation anyway, so last_visit_id is always zero for them.  But adding
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // them here confuses main frame history, so we skip them for now.
5861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (stripped_transition != ui::PAGE_TRANSITION_AUTO_SUBFRAME &&
5871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      stripped_transition != ui::PAGE_TRANSITION_MANUAL_SUBFRAME &&
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !is_keyword_generated) {
589f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    tracker_.AddVisit(request.context_id, request.page_id, request.url,
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      last_ids.second);
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::InitImpl(const std::string& languages) {
597b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  DCHECK(!db_) << "Initializing HistoryBackend twice";
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // In the rare case where the db fails to initialize a dialog may get shown
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the blocks the caller, yet allows other messages through. For this reason
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // we only set db_ to the created database if creation is successful. That
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // way other methods won't do anything as db_ is still NULL.
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TimeTicks beginning_time = TimeTicks::Now();
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
605bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // Compute the file names.
6062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath history_name = history_dir_.Append(chrome::kHistoryFilename);
6073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  base::FilePath thumbnail_name = GetFaviconsFileName();
6082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath archived_name = GetArchivedFileName();
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
610bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // Delete the old index database files which are no longer used.
611bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  DeleteFTSIndexDatabases();
612bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // History database.
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_.reset(new HistoryDatabase());
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6167d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // Unretained to avoid a ref loop with db_.
6177d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  db_->set_error_callback(
6187d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      base::Bind(&HistoryBackend::DatabaseErrorCallback,
6197d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                 base::Unretained(this)));
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6217d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  sql::InitStatus status = db_->Init(history_name);
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (status) {
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case sql::INIT_OK:
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case sql::INIT_FAILURE: {
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // A NULL db_ will cause all calls on this object to notice this error
6277d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      // and to not continue. If the error callback scheduled killing the
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // database, the task it posted has not executed yet. Try killing the
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // database now before we close it.
6307d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      bool kill_db = scheduled_kill_db_;
6317d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      if (kill_db)
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        KillHistoryDatabase();
6337d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      UMA_HISTOGRAM_BOOLEAN("History.AttemptedToFixProfileError", kill_db);
634a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      delegate_->NotifyProfileError(status);
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_.reset();
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Fill the in-memory database and send it back to the history service on the
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // main thread.
644a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  {
645a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    scoped_ptr<InMemoryHistoryBackend> mem_backend(new InMemoryHistoryBackend);
646116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (mem_backend->Init(history_name))
647a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      delegate_->SetInMemoryBackend(mem_backend.Pass());
648a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->BeginExclusiveMode();  // Must be after the mem backend read the data.
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Thumbnail database.
6523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // TODO(shess): "thumbnail database" these days only stores
6533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // favicons.  Thumbnails are stored in "top sites".  Consider
6543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // renaming "thumbnail" references to "favicons" or something of the
6553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // sort.
656116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  thumbnail_db_.reset(new ThumbnailDatabase(history_client_));
6574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (thumbnail_db_->Init(thumbnail_name) != sql::INIT_OK) {
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Unlike the main database, we don't error out when the database is too
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // new because this error is much less severe. Generally, this shouldn't
66058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // happen since the thumbnail and main database versions should be in sync.
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We'll just continue without thumbnails & favicons in this case or any
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // other error.
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "Could not initialize the thumbnail database.";
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_.reset();
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
66746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // Nuke any files corresponding to the legacy Archived History Database, which
66846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // previously retained expired (> 3 months old) history entries, but, in the
66946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // end, was not used for much, and consequently has been removed as of M37.
67046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // TODO(engedy): Remove this code after the end of 2014.
67146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  sql::Connection::Delete(archived_name);
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Generate the history and thumbnail database metrics only after performing
6742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // any migration work.
6752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (base::RandInt(1, 100) == 50) {
6762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Only do this computation sometimes since it can be expensive.
6772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    db_->ComputeDatabaseMetrics(history_name);
6782385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    if (thumbnail_db_)
6792385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch      thumbnail_db_->ComputeDatabaseMetrics();
6802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
68246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  expirer_.SetDatabases(db_.get(), thumbnail_db_.get());
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Open the long-running transaction.
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->BeginTransaction();
686b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (thumbnail_db_)
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_->BeginTransaction();
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the first item in our database.
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->GetStartDate(&first_recorded_time_);
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Start expiring old stuff.
69346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  expirer_.StartExpiringOldStuff(TimeDelta::FromDays(kExpireDaysThreshold));
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
696b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (thumbnail_db_) {
69746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    android_provider_backend_.reset(
69846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        new AndroidProviderBackend(GetAndroidCacheFileName(),
69946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                   db_.get(),
70046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                   thumbnail_db_.get(),
70146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                   history_client_,
70246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                   delegate_.get()));
7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  LOCAL_HISTOGRAM_TIMES("History.InitTime", TimeTicks::Now() - beginning_time);
7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
709ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochvoid HistoryBackend::OnMemoryPressure(
710ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
711ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  bool trim_aggressively = memory_pressure_level ==
712ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      base::MemoryPressureListener::MEMORY_PRESSURE_CRITICAL;
713ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (db_)
714ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    db_->TrimMemory(trim_aggressively);
715ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (thumbnail_db_)
716ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    thumbnail_db_->TrimMemory(trim_aggressively);
717ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
718ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::CloseAllDatabases() {
720b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Commit the long-running transaction.
7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_->CommitTransaction();
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_.reset();
72458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // Forget the first recorded time since the database is closed.
72558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    first_recorded_time_ = base::Time();
7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
727b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (thumbnail_db_) {
7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_->CommitTransaction();
7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_.reset();
7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::pair<URLID, VisitID> HistoryBackend::AddPageVisit(
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url,
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Time time,
7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitID referring_visit,
7371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    ui::PageTransition transition,
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitSource visit_source) {
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Top-level frame navigations are visible, everything else is hidden
7401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  bool new_hidden = !ui::PageTransitionIsMainFrame(transition);
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // NOTE: This code must stay in sync with
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ExpireHistoryBackend::ExpireURLsForVisits().
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(pkasting): http://b/1148304 We shouldn't be marking so many URLs as
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // typed, which would eliminate the need for this code.
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int typed_increment = 0;
7471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ui::PageTransition transition_type =
7481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      ui::PageTransitionStripQualifier(transition);
7491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if ((transition_type == ui::PAGE_TRANSITION_TYPED &&
7501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      !ui::PageTransitionIsRedirect(transition)) ||
7511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      transition_type == ui::PAGE_TRANSITION_KEYWORD_GENERATED)
7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    typed_increment = 1;
7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
754eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#if defined(OS_ANDROID)
755eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Only count the page visit if it came from user browsing and only count it
756eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // once when cycling through a redirect chain.
757eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (visit_source == SOURCE_BROWSED &&
7581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      (transition & ui::PAGE_TRANSITION_CHAIN_END) != 0) {
759eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    RecordTopPageVisitStats(url);
760eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
761eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif
762eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // See if this URL is already in the DB.
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLRow url_info(url);
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLID url_id = db_->GetRowForURL(url, &url_info);
7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (url_id) {
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Update of an existing row.
7681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (ui::PageTransitionStripQualifier(transition) !=
7691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        ui::PAGE_TRANSITION_RELOAD)
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url_info.set_visit_count(url_info.visit_count() + 1);
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (typed_increment)
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url_info.set_typed_count(url_info.typed_count() + typed_increment);
773c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (url_info.last_visit() < time)
774c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      url_info.set_last_visit(time);
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Only allow un-hiding of pages, never hiding.
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!new_hidden)
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url_info.set_hidden(false);
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_->UpdateURLRow(url_id, url_info);
7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Addition of a new row.
7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_info.set_visit_count(1);
7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_info.set_typed_count(typed_increment);
7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_info.set_last_visit(time);
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_info.set_hidden(new_hidden);
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_id = db_->AddURL(url_info);
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!url_id) {
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED() << "Adding URL failed.";
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return std::make_pair(0, 0);
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_info.id_ = url_id;
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Add the visit with the time to the database.
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitRow visit_info(url_id, time, referring_visit, transition, 0);
7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitID visit_id = db_->AddVisit(&visit_info, visit_source);
7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NotifyVisitObservers(visit_info);
8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (visit_info.visit_time < first_recorded_time_)
8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    first_recorded_time_ = visit_info.visit_time;
8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Broadcast a notification of the visit.
8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (visit_id) {
806b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (typed_url_syncable_service_.get())
807b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      typed_url_syncable_service_->OnUrlVisited(transition, &url_info);
808b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
809a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    scoped_ptr<URLVisitedDetails> details(new URLVisitedDetails);
8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    details->transition = transition;
8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    details->row = url_info;
812cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    details->visit_time = time;
8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(meelapshah) Disabled due to potential PageCycler regression.
8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Re-enable this.
815116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // QueryRedirectsTo(url, &details->redirects);
816a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URL_VISITED,
817a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                           details.PassAs<HistoryDetails>());
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VLOG(0) << "Failed to build visit insert statement:  "
8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            << "url_id = " << url_id;
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return std::make_pair(url_id, visit_id);
8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::AddPagesWithDetails(const URLRows& urls,
8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         VisitSource visit_source) {
828b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<URLsModifiedDetails> modified(new URLsModifiedDetails);
8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (URLRows::const_iterator i = urls.begin(); i != urls.end(); ++i) {
8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!i->last_visit().is_null());
8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
83546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    // As of M37, we no longer maintain an archived database, ignore old visits.
83646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (IsExpiredVisitTime(i->last_visit()))
83746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      continue;
8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLRow existing_url;
84046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    URLID url_id = db_->GetRowForURL(i->url(), &existing_url);
8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!url_id) {
8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Add the page if it doesn't exist.
84346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      url_id = db_->AddURL(*i);
8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!url_id) {
8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NOTREACHED() << "Could not add row to DB";
8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
849f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      modified->changed_urls.push_back(*i);
850f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      modified->changed_urls.back().set_id(url_id);  // i->id_ is likely 0.
8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Sync code manages the visits itself.
8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (visit_source != SOURCE_SYNCED) {
8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Make up a visit to correspond to the last visit to the page.
8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VisitRow visit_info(url_id, i->last_visit(), 0,
8571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                          ui::PageTransitionFromInt(
8581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                              ui::PAGE_TRANSITION_LINK |
8591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                              ui::PAGE_TRANSITION_CHAIN_START |
8601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                              ui::PAGE_TRANSITION_CHAIN_END), 0);
86146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      if (!db_->AddVisit(&visit_info, visit_source)) {
8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NOTREACHED() << "Adding visit failed.";
8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NotifyVisitObservers(visit_info);
8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (visit_info.visit_time < first_recorded_time_)
8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        first_recorded_time_ = visit_info.visit_time;
8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
87246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (typed_url_syncable_service_.get())
873b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    typed_url_syncable_service_->OnUrlsModified(&modified->changed_urls);
874b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Broadcast a notification for typed URLs that have been modified. This
8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // will be picked up by the in-memory URL database on the main thread.
8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(brettw) bug 1140015: Add an "add page" notification so the history
8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // views can keep in sync.
8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED,
881a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                         modified.PassAs<HistoryDetails>());
8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::IsExpiredVisitTime(const base::Time& time) {
88746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  return time < expirer_.GetCurrentExpirationTime();
8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
890a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void HistoryBackend::SetPageTitle(const GURL& url,
891a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                  const base::string16& title) {
892b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Search for recent redirects which should get the same title. We make a
8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // dummy list containing the exact URL visited if there are no redirects so
8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the processing below can be the same.
8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  history::RedirectList dummy_list;
8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  history::RedirectList* redirects;
9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RedirectCache::iterator iter = recent_redirects_.Get(url);
9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (iter != recent_redirects_.end()) {
9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    redirects = &iter->second;
9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This redirect chain should have the destination URL as the last item.
9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!redirects->empty());
9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(redirects->back() == url);
9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No redirect chain stored, make up one containing the URL we want so we
9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // can use the same logic below.
9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dummy_list.push_back(url);
9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    redirects = &dummy_list;
9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<URLsModifiedDetails> details(new URLsModifiedDetails);
9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < redirects->size(); i++) {
9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLRow row;
9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLID row_id = db_->GetRowForURL(redirects->at(i), &row);
9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (row_id && row.title() != title) {
9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      row.set_title(title);
9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_->UpdateURLRow(row_id, row);
9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      details->changed_urls.push_back(row);
9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Broadcast notifications for any URLs that have changed. This will
9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // update the in-memory database and the InMemoryURLIndex.
9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!details->changed_urls.empty()) {
928b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (typed_url_syncable_service_.get())
929b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      typed_url_syncable_service_->OnUrlsModified(&details->changed_urls);
9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED,
931a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                           details.PassAs<HistoryDetails>());
9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ScheduleCommit();
9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::AddPageNoVisitForBookmark(const GURL& url,
937a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                               const base::string16& title) {
938b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLRow url_info(url);
9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLID url_id = db_->GetRowForURL(url, &url_info);
9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (url_id) {
9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // URL is already known, nothing to do.
9455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!title.empty()) {
9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_info.set_title(title);
9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
9515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    url_info.set_title(base::UTF8ToUTF16(url.spec()));
9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  url_info.set_last_visit(Time::Now());
9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Mark the page hidden. If the user types it in, it'll unhide.
9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  url_info.set_hidden(true);
9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->AddURL(url_info);
9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::IterateURLs(
96290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const scoped_refptr<visitedlink::VisitedLinkDelegate::URLEnumerator>&
9632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    iterator) {
964b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HistoryDatabase::URLEnumerator e;
9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (db_->InitURLEnumeratorForEverything(&e)) {
9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      URLRow info;
9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      while (e.GetNextURL(&info)) {
9692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        iterator->OnURL(info.url());
9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      iterator->OnComplete(true);  // Success.
9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  iterator->OnComplete(false);  // Failure.
9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetAllTypedURLs(URLRows* urls) {
979b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_)
9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return db_->GetAllTypedUrls(urls);
9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetVisitsForURL(URLID id, VisitVector* visits) {
985b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_)
9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return db_->GetVisitsForURL(id, visits);
9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
988