c30c6aa80b20e5a17b8b6b31510a802321a17022
[platform/framework/web/crosswalk.git] / src / chrome / browser / history / history_backend.cc
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/history/history_backend.h"
6
7 #include <algorithm>
8 #include <functional>
9 #include <list>
10 #include <map>
11 #include <set>
12 #include <vector>
13
14 #include "base/basictypes.h"
15 #include "base/bind.h"
16 #include "base/compiler_specific.h"
17 #include "base/files/file_enumerator.h"
18 #include "base/memory/scoped_ptr.h"
19 #include "base/memory/scoped_vector.h"
20 #include "base/message_loop/message_loop.h"
21 #include "base/metrics/histogram.h"
22 #include "base/rand_util.h"
23 #include "base/strings/string_util.h"
24 #include "base/strings/utf_string_conversions.h"
25 #include "base/time/time.h"
26 #include "chrome/browser/autocomplete/history_url_provider.h"
27 #include "chrome/browser/chrome_notification_types.h"
28 #include "chrome/browser/favicon/favicon_changed_details.h"
29 #include "chrome/browser/history/download_row.h"
30 #include "chrome/browser/history/history_db_task.h"
31 #include "chrome/browser/history/history_notifications.h"
32 #include "chrome/browser/history/in_memory_history_backend.h"
33 #include "chrome/browser/history/page_usage_data.h"
34 #include "chrome/browser/history/top_sites.h"
35 #include "chrome/browser/history/typed_url_syncable_service.h"
36 #include "chrome/browser/history/visit_filter.h"
37 #include "chrome/common/chrome_constants.h"
38 #include "chrome/common/importer/imported_favicon_usage.h"
39 #include "chrome/common/url_constants.h"
40 #include "components/favicon_base/select_favicon_frames.h"
41 #include "components/history/core/browser/history_client.h"
42 #include "grit/chromium_strings.h"
43 #include "grit/generated_resources.h"
44 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
45 #include "sql/error_delegate_util.h"
46 #include "url/gurl.h"
47
48 #if defined(OS_ANDROID)
49 #include "chrome/browser/history/android/android_provider_backend.h"
50 #endif
51
52 using base::Time;
53 using base::TimeDelta;
54 using base::TimeTicks;
55
56 /* The HistoryBackend consists of two components:
57
58     HistoryDatabase (stores past 3 months of history)
59       URLDatabase (stores a list of URLs)
60       DownloadDatabase (stores a list of downloads)
61       VisitDatabase (stores a list of visits for the URLs)
62       VisitSegmentDatabase (stores groups of URLs for the most visited view).
63
64     ExpireHistoryBackend (manages deleting things older than 3 months)
65 */
66
67 namespace history {
68
69 // How long we keep segment data for in days. Currently 3 months.
70 // This value needs to be greater or equal to
71 // MostVisitedModel::kMostVisitedScope but we don't want to introduce a direct
72 // dependency between MostVisitedModel and the history backend.
73 const int kSegmentDataRetention = 90;
74
75 // How long we'll wait to do a commit, so that things are batched together.
76 const int kCommitIntervalSeconds = 10;
77
78 // The amount of time before we re-fetch the favicon.
79 const int kFaviconRefetchDays = 7;
80
81 // The maximum number of items we'll allow in the redirect list before
82 // deleting some.
83 const int kMaxRedirectCount = 32;
84
85 // The number of days old a history entry can be before it is considered "old"
86 // and is deleted.
87 const int kExpireDaysThreshold = 90;
88
89 #if defined(OS_ANDROID)
90 // The maximum number of top sites to track when recording top page visit stats.
91 const size_t kPageVisitStatsMaxTopSites = 50;
92 #endif
93
94 // Converts from PageUsageData to MostVisitedURL. |redirects| is a
95 // list of redirects for this URL. Empty list means no redirects.
96 MostVisitedURL MakeMostVisitedURL(const PageUsageData& page_data,
97                                   const RedirectList& redirects) {
98   MostVisitedURL mv;
99   mv.url = page_data.GetURL();
100   mv.title = page_data.GetTitle();
101   if (redirects.empty()) {
102     // Redirects must contain at least the target url.
103     mv.redirects.push_back(mv.url);
104   } else {
105     mv.redirects = redirects;
106     if (mv.redirects[mv.redirects.size() - 1] != mv.url) {
107       // The last url must be the target url.
108       mv.redirects.push_back(mv.url);
109     }
110   }
111   return mv;
112 }
113
114 // This task is run on a timer so that commits happen at regular intervals
115 // so they are batched together. The important thing about this class is that
116 // it supports canceling of the task so the reference to the backend will be
117 // freed. The problem is that when history is shutting down, there is likely
118 // to be one of these commits still pending and holding a reference.
119 //
120 // The backend can call Cancel to have this task release the reference. The
121 // task will still run (if we ever get to processing the event before
122 // shutdown), but it will not do anything.
123 //
124 // Note that this is a refcounted object and is not a task in itself. It should
125 // be assigned to a RunnableMethod.
126 //
127 // TODO(brettw): bug 1165182: This should be replaced with a
128 // base::WeakPtrFactory which will handle everything automatically (like we do
129 // in ExpireHistoryBackend).
130 class CommitLaterTask : public base::RefCounted<CommitLaterTask> {
131  public:
132   explicit CommitLaterTask(HistoryBackend* history_backend)
133       : history_backend_(history_backend) {
134   }
135
136   // The backend will call this function if it is being destroyed so that we
137   // release our reference.
138   void Cancel() {
139     history_backend_ = NULL;
140   }
141
142   void RunCommit() {
143     if (history_backend_.get())
144       history_backend_->Commit();
145   }
146
147  private:
148   friend class base::RefCounted<CommitLaterTask>;
149
150   ~CommitLaterTask() {}
151
152   scoped_refptr<HistoryBackend> history_backend_;
153 };
154
155 // HistoryBackend::QueryURLResult ----------------------------------------------
156
157 HistoryBackend::QueryURLResult::QueryURLResult() : success(false) {
158 }
159
160 HistoryBackend::QueryURLResult::~QueryURLResult() {
161 }
162
163 // HistoryBackend --------------------------------------------------------------
164
165 HistoryBackend::HistoryBackend(const base::FilePath& history_dir,
166                                Delegate* delegate,
167                                HistoryClient* history_client)
168     : delegate_(delegate),
169       history_dir_(history_dir),
170       scheduled_kill_db_(false),
171       expirer_(this, history_client),
172       recent_redirects_(kMaxRedirectCount),
173       backend_destroy_message_loop_(NULL),
174       segment_queried_(false),
175       history_client_(history_client) {
176 }
177
178 HistoryBackend::~HistoryBackend() {
179   DCHECK(!scheduled_commit_.get()) << "Deleting without cleanup";
180   ReleaseDBTasks();
181
182 #if defined(OS_ANDROID)
183   // Release AndroidProviderBackend before other objects.
184   android_provider_backend_.reset();
185 #endif
186
187   // First close the databases before optionally running the "destroy" task.
188   CloseAllDatabases();
189
190   if (!backend_destroy_task_.is_null()) {
191     // Notify an interested party (typically a unit test) that we're done.
192     DCHECK(backend_destroy_message_loop_);
193     backend_destroy_message_loop_->PostTask(FROM_HERE, backend_destroy_task_);
194   }
195
196 #if defined(OS_ANDROID)
197   sql::Connection::Delete(GetAndroidCacheFileName());
198 #endif
199 }
200
201 void HistoryBackend::Init(const std::string& languages, bool force_fail) {
202   if (!force_fail)
203     InitImpl(languages);
204   delegate_->DBLoaded();
205   typed_url_syncable_service_.reset(new TypedUrlSyncableService(this));
206   memory_pressure_listener_.reset(new base::MemoryPressureListener(
207       base::Bind(&HistoryBackend::OnMemoryPressure, base::Unretained(this))));
208 #if defined(OS_ANDROID)
209   PopulateMostVisitedURLMap();
210 #endif
211 }
212
213 void HistoryBackend::SetOnBackendDestroyTask(base::MessageLoop* message_loop,
214                                              const base::Closure& task) {
215   if (!backend_destroy_task_.is_null())
216     DLOG(WARNING) << "Setting more than one destroy task, overriding";
217   backend_destroy_message_loop_ = message_loop;
218   backend_destroy_task_ = task;
219 }
220
221 void HistoryBackend::Closing() {
222   // Any scheduled commit will have a reference to us, we must make it
223   // release that reference before we can be destroyed.
224   CancelScheduledCommit();
225
226   // Release our reference to the delegate, this reference will be keeping the
227   // history service alive.
228   delegate_.reset();
229 }
230
231 void HistoryBackend::ClearCachedDataForContextID(ContextID context_id) {
232   tracker_.ClearCachedDataForContextID(context_id);
233 }
234
235 base::FilePath HistoryBackend::GetThumbnailFileName() const {
236   return history_dir_.Append(chrome::kThumbnailsFilename);
237 }
238
239 base::FilePath HistoryBackend::GetFaviconsFileName() const {
240   return history_dir_.Append(chrome::kFaviconsFilename);
241 }
242
243 base::FilePath HistoryBackend::GetArchivedFileName() const {
244   return history_dir_.Append(chrome::kArchivedHistoryFilename);
245 }
246
247 #if defined(OS_ANDROID)
248 base::FilePath HistoryBackend::GetAndroidCacheFileName() const {
249   return history_dir_.Append(chrome::kAndroidCacheFilename);
250 }
251 #endif
252
253 SegmentID HistoryBackend::GetLastSegmentID(VisitID from_visit) {
254   // Set is used to detect referrer loops.  Should not happen, but can
255   // if the database is corrupt.
256   std::set<VisitID> visit_set;
257   VisitID visit_id = from_visit;
258   while (visit_id) {
259     VisitRow row;
260     if (!db_->GetRowForVisit(visit_id, &row))
261       return 0;
262     if (row.segment_id)
263       return row.segment_id;  // Found a visit in this change with a segment.
264
265     // Check the referrer of this visit, if any.
266     visit_id = row.referring_visit;
267
268     if (visit_set.find(visit_id) != visit_set.end()) {
269       NOTREACHED() << "Loop in referer chain, giving up";
270       break;
271     }
272     visit_set.insert(visit_id);
273   }
274   return 0;
275 }
276
277 SegmentID HistoryBackend::UpdateSegments(
278     const GURL& url,
279     VisitID from_visit,
280     VisitID visit_id,
281     content::PageTransition transition_type,
282     const Time ts) {
283   if (!db_)
284     return 0;
285
286   // We only consider main frames.
287   if (!content::PageTransitionIsMainFrame(transition_type))
288     return 0;
289
290   SegmentID segment_id = 0;
291   content::PageTransition t =
292       content::PageTransitionStripQualifier(transition_type);
293
294   // Are we at the beginning of a new segment?
295   // Note that navigating to an existing entry (with back/forward) reuses the
296   // same transition type.  We are not adding it as a new segment in that case
297   // because if this was the target of a redirect, we might end up with
298   // 2 entries for the same final URL. Ex: User types google.net, gets
299   // redirected to google.com. A segment is created for google.net. On
300   // google.com users navigates through a link, then press back. That last
301   // navigation is for the entry google.com transition typed. We end up adding
302   // a segment for that one as well. So we end up with google.net and google.com
303   // in the segment table, showing as 2 entries in the NTP.
304   // Note also that we should still be updating the visit count for that segment
305   // which we are not doing now. It should be addressed when
306   // http://crbug.com/96860 is fixed.
307   if ((t == content::PAGE_TRANSITION_TYPED ||
308        t == content::PAGE_TRANSITION_AUTO_BOOKMARK) &&
309       (transition_type & content::PAGE_TRANSITION_FORWARD_BACK) == 0) {
310     // If so, create or get the segment.
311     std::string segment_name = db_->ComputeSegmentName(url);
312     URLID url_id = db_->GetRowForURL(url, NULL);
313     if (!url_id)
314       return 0;
315
316     if (!(segment_id = db_->GetSegmentNamed(segment_name))) {
317       if (!(segment_id = db_->CreateSegment(url_id, segment_name))) {
318         NOTREACHED();
319         return 0;
320       }
321     } else {
322       // Note: if we update an existing segment, we update the url used to
323       // represent that segment in order to minimize stale most visited
324       // images.
325       db_->UpdateSegmentRepresentationURL(segment_id, url_id);
326     }
327   } else {
328     // Note: it is possible there is no segment ID set for this visit chain.
329     // This can happen if the initial navigation wasn't AUTO_BOOKMARK or
330     // TYPED. (For example GENERATED). In this case this visit doesn't count
331     // toward any segment.
332     if (!(segment_id = GetLastSegmentID(from_visit)))
333       return 0;
334   }
335
336   // Set the segment in the visit.
337   if (!db_->SetSegmentID(visit_id, segment_id)) {
338     NOTREACHED();
339     return 0;
340   }
341
342   // Finally, increase the counter for that segment / day.
343   if (!db_->IncreaseSegmentVisitCount(segment_id, ts, 1)) {
344     NOTREACHED();
345     return 0;
346   }
347   return segment_id;
348 }
349
350 void HistoryBackend::UpdateWithPageEndTime(ContextID context_id,
351                                            int32 page_id,
352                                            const GURL& url,
353                                            Time end_ts) {
354   // Will be filled with the URL ID and the visit ID of the last addition.
355   VisitID visit_id = tracker_.GetLastVisit(context_id, page_id, url);
356   UpdateVisitDuration(visit_id, end_ts);
357 }
358
359 void HistoryBackend::UpdateVisitDuration(VisitID visit_id, const Time end_ts) {
360   if (!db_)
361     return;
362
363   // Get the starting visit_time for visit_id.
364   VisitRow visit_row;
365   if (db_->GetRowForVisit(visit_id, &visit_row)) {
366     // We should never have a negative duration time even when time is skewed.
367     visit_row.visit_duration = end_ts > visit_row.visit_time ?
368         end_ts - visit_row.visit_time : TimeDelta::FromMicroseconds(0);
369     db_->UpdateVisitRow(visit_row);
370   }
371 }
372
373 void HistoryBackend::AddPage(const HistoryAddPageArgs& request) {
374   if (!db_)
375     return;
376
377   // Will be filled with the URL ID and the visit ID of the last addition.
378   std::pair<URLID, VisitID> last_ids(0, tracker_.GetLastVisit(
379       request.context_id, request.page_id, request.referrer));
380
381   VisitID from_visit_id = last_ids.second;
382
383   // If a redirect chain is given, we expect the last item in that chain to be
384   // the final URL.
385   DCHECK(request.redirects.empty() ||
386          request.redirects.back() == request.url);
387
388   // If the user is adding older history, we need to make sure our times
389   // are correct.
390   if (request.time < first_recorded_time_)
391     first_recorded_time_ = request.time;
392
393   content::PageTransition request_transition = request.transition;
394   content::PageTransition stripped_transition =
395     content::PageTransitionStripQualifier(request_transition);
396   bool is_keyword_generated =
397       (stripped_transition == content::PAGE_TRANSITION_KEYWORD_GENERATED);
398
399   // If the user is navigating to a not-previously-typed intranet hostname,
400   // change the transition to TYPED so that the omnibox will learn that this is
401   // a known host.
402   bool has_redirects = request.redirects.size() > 1;
403   if (content::PageTransitionIsMainFrame(request_transition) &&
404       (stripped_transition != content::PAGE_TRANSITION_TYPED) &&
405       !is_keyword_generated) {
406     const GURL& origin_url(has_redirects ?
407         request.redirects[0] : request.url);
408     if (origin_url.SchemeIs(url::kHttpScheme) ||
409         origin_url.SchemeIs(url::kHttpsScheme) ||
410         origin_url.SchemeIs(url::kFtpScheme)) {
411       std::string host(origin_url.host());
412       size_t registry_length =
413           net::registry_controlled_domains::GetRegistryLength(
414               host,
415               net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES,
416               net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
417       if (registry_length == 0 && !db_->IsTypedHost(host)) {
418         stripped_transition = content::PAGE_TRANSITION_TYPED;
419         request_transition =
420             content::PageTransitionFromInt(
421                 stripped_transition |
422                 content::PageTransitionGetQualifier(request_transition));
423       }
424     }
425   }
426
427   if (!has_redirects) {
428     // The single entry is both a chain start and end.
429     content::PageTransition t = content::PageTransitionFromInt(
430         request_transition |
431         content::PAGE_TRANSITION_CHAIN_START |
432         content::PAGE_TRANSITION_CHAIN_END);
433
434     // No redirect case (one element means just the page itself).
435     last_ids = AddPageVisit(request.url, request.time,
436                             last_ids.second, t, request.visit_source);
437
438     // Update the segment for this visit. KEYWORD_GENERATED visits should not
439     // result in changing most visited, so we don't update segments (most
440     // visited db).
441     if (!is_keyword_generated) {
442       UpdateSegments(request.url, from_visit_id, last_ids.second, t,
443                      request.time);
444
445       // Update the referrer's duration.
446       UpdateVisitDuration(from_visit_id, request.time);
447     }
448   } else {
449     // Redirect case. Add the redirect chain.
450
451     content::PageTransition redirect_info =
452         content::PAGE_TRANSITION_CHAIN_START;
453
454     RedirectList redirects = request.redirects;
455     if (redirects[0].SchemeIs(url::kAboutScheme)) {
456       // When the redirect source + referrer is "about" we skip it. This
457       // happens when a page opens a new frame/window to about:blank and then
458       // script sets the URL to somewhere else (used to hide the referrer). It
459       // would be nice to keep all these redirects properly but we don't ever
460       // see the initial about:blank load, so we don't know where the
461       // subsequent client redirect came from.
462       //
463       // In this case, we just don't bother hooking up the source of the
464       // redirects, so we remove it.
465       redirects.erase(redirects.begin());
466     } else if (request_transition & content::PAGE_TRANSITION_CLIENT_REDIRECT) {
467       redirect_info = content::PAGE_TRANSITION_CLIENT_REDIRECT;
468       // The first entry in the redirect chain initiated a client redirect.
469       // We don't add this to the database since the referrer is already
470       // there, so we skip over it but change the transition type of the first
471       // transition to client redirect.
472       //
473       // The referrer is invalid when restoring a session that features an
474       // https tab that redirects to a different host or to http. In this
475       // case we don't need to reconnect the new redirect with the existing
476       // chain.
477       if (request.referrer.is_valid()) {
478         DCHECK(request.referrer == redirects[0]);
479         redirects.erase(redirects.begin());
480
481         // If the navigation entry for this visit has replaced that for the
482         // first visit, remove the CHAIN_END marker from the first visit. This
483         // can be called a lot, for example, the page cycler, and most of the
484         // time we won't have changed anything.
485         VisitRow visit_row;
486         if (request.did_replace_entry &&
487             db_->GetRowForVisit(last_ids.second, &visit_row) &&
488             visit_row.transition & content::PAGE_TRANSITION_CHAIN_END) {
489           visit_row.transition = content::PageTransitionFromInt(
490               visit_row.transition & ~content::PAGE_TRANSITION_CHAIN_END);
491           db_->UpdateVisitRow(visit_row);
492         }
493       }
494     }
495
496     for (size_t redirect_index = 0; redirect_index < redirects.size();
497          redirect_index++) {
498       content::PageTransition t =
499           content::PageTransitionFromInt(stripped_transition | redirect_info);
500
501       // If this is the last transition, add a CHAIN_END marker
502       if (redirect_index == (redirects.size() - 1)) {
503         t = content::PageTransitionFromInt(
504             t | content::PAGE_TRANSITION_CHAIN_END);
505       }
506
507       // Record all redirect visits with the same timestamp. We don't display
508       // them anyway, and if we ever decide to, we can reconstruct their order
509       // from the redirect chain.
510       last_ids = AddPageVisit(redirects[redirect_index],
511                               request.time, last_ids.second,
512                               t, request.visit_source);
513       if (t & content::PAGE_TRANSITION_CHAIN_START) {
514         // Update the segment for this visit.
515         UpdateSegments(redirects[redirect_index],
516                        from_visit_id, last_ids.second, t, request.time);
517
518         // Update the visit_details for this visit.
519         UpdateVisitDuration(from_visit_id, request.time);
520       }
521
522       // Subsequent transitions in the redirect list must all be server
523       // redirects.
524       redirect_info = content::PAGE_TRANSITION_SERVER_REDIRECT;
525     }
526
527     // Last, save this redirect chain for later so we can set titles & favicons
528     // on the redirected pages properly.
529     recent_redirects_.Put(request.url, redirects);
530   }
531
532   // TODO(brettw) bug 1140015: Add an "add page" notification so the history
533   // views can keep in sync.
534
535   // Add the last visit to the tracker so we can get outgoing transitions.
536   // TODO(evanm): Due to http://b/1194536 we lose the referrers of a subframe
537   // navigation anyway, so last_visit_id is always zero for them.  But adding
538   // them here confuses main frame history, so we skip them for now.
539   if (stripped_transition != content::PAGE_TRANSITION_AUTO_SUBFRAME &&
540       stripped_transition != content::PAGE_TRANSITION_MANUAL_SUBFRAME &&
541       !is_keyword_generated) {
542     tracker_.AddVisit(request.context_id, request.page_id, request.url,
543                       last_ids.second);
544   }
545
546   ScheduleCommit();
547 }
548
549 void HistoryBackend::InitImpl(const std::string& languages) {
550   DCHECK(!db_) << "Initializing HistoryBackend twice";
551   // In the rare case where the db fails to initialize a dialog may get shown
552   // the blocks the caller, yet allows other messages through. For this reason
553   // we only set db_ to the created database if creation is successful. That
554   // way other methods won't do anything as db_ is still NULL.
555
556   TimeTicks beginning_time = TimeTicks::Now();
557
558   // Compute the file names.
559   base::FilePath history_name = history_dir_.Append(chrome::kHistoryFilename);
560   base::FilePath thumbnail_name = GetFaviconsFileName();
561   base::FilePath archived_name = GetArchivedFileName();
562
563   // Delete the old index database files which are no longer used.
564   DeleteFTSIndexDatabases();
565
566   // History database.
567   db_.reset(new HistoryDatabase());
568
569   // Unretained to avoid a ref loop with db_.
570   db_->set_error_callback(
571       base::Bind(&HistoryBackend::DatabaseErrorCallback,
572                  base::Unretained(this)));
573
574   sql::InitStatus status = db_->Init(history_name);
575   switch (status) {
576     case sql::INIT_OK:
577       break;
578     case sql::INIT_FAILURE: {
579       // A NULL db_ will cause all calls on this object to notice this error
580       // and to not continue. If the error callback scheduled killing the
581       // database, the task it posted has not executed yet. Try killing the
582       // database now before we close it.
583       bool kill_db = scheduled_kill_db_;
584       if (kill_db)
585         KillHistoryDatabase();
586       UMA_HISTOGRAM_BOOLEAN("History.AttemptedToFixProfileError", kill_db);
587       delegate_->NotifyProfileError(status);
588       db_.reset();
589       return;
590     }
591     default:
592       NOTREACHED();
593   }
594
595   // Fill the in-memory database and send it back to the history service on the
596   // main thread.
597   {
598     scoped_ptr<InMemoryHistoryBackend> mem_backend(new InMemoryHistoryBackend);
599     if (mem_backend->Init(history_name, db_.get()))
600       delegate_->SetInMemoryBackend(mem_backend.Pass());
601   }
602   db_->BeginExclusiveMode();  // Must be after the mem backend read the data.
603
604   // Thumbnail database.
605   // TODO(shess): "thumbnail database" these days only stores
606   // favicons.  Thumbnails are stored in "top sites".  Consider
607   // renaming "thumbnail" references to "favicons" or something of the
608   // sort.
609   thumbnail_db_.reset(new ThumbnailDatabase());
610   if (thumbnail_db_->Init(thumbnail_name) != sql::INIT_OK) {
611     // Unlike the main database, we don't error out when the database is too
612     // new because this error is much less severe. Generally, this shouldn't
613     // happen since the thumbnail and main database versions should be in sync.
614     // We'll just continue without thumbnails & favicons in this case or any
615     // other error.
616     LOG(WARNING) << "Could not initialize the thumbnail database.";
617     thumbnail_db_.reset();
618   }
619
620   // Nuke any files corresponding to the legacy Archived History Database, which
621   // previously retained expired (> 3 months old) history entries, but, in the
622   // end, was not used for much, and consequently has been removed as of M37.
623   // TODO(engedy): Remove this code after the end of 2014.
624   sql::Connection::Delete(archived_name);
625
626   // Generate the history and thumbnail database metrics only after performing
627   // any migration work.
628   if (base::RandInt(1, 100) == 50) {
629     // Only do this computation sometimes since it can be expensive.
630     db_->ComputeDatabaseMetrics(history_name);
631     if (thumbnail_db_)
632       thumbnail_db_->ComputeDatabaseMetrics();
633   }
634
635   expirer_.SetDatabases(db_.get(), thumbnail_db_.get());
636
637   // Open the long-running transaction.
638   db_->BeginTransaction();
639   if (thumbnail_db_)
640     thumbnail_db_->BeginTransaction();
641
642   // Get the first item in our database.
643   db_->GetStartDate(&first_recorded_time_);
644
645   // Start expiring old stuff.
646   expirer_.StartExpiringOldStuff(TimeDelta::FromDays(kExpireDaysThreshold));
647
648 #if defined(OS_ANDROID)
649   if (thumbnail_db_) {
650     android_provider_backend_.reset(
651         new AndroidProviderBackend(GetAndroidCacheFileName(),
652                                    db_.get(),
653                                    thumbnail_db_.get(),
654                                    history_client_,
655                                    delegate_.get()));
656   }
657 #endif
658
659   HISTOGRAM_TIMES("History.InitTime",
660                   TimeTicks::Now() - beginning_time);
661 }
662
663 void HistoryBackend::OnMemoryPressure(
664     base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
665   bool trim_aggressively = memory_pressure_level ==
666       base::MemoryPressureListener::MEMORY_PRESSURE_CRITICAL;
667   if (db_)
668     db_->TrimMemory(trim_aggressively);
669   if (thumbnail_db_)
670     thumbnail_db_->TrimMemory(trim_aggressively);
671 }
672
673 void HistoryBackend::CloseAllDatabases() {
674   if (db_) {
675     // Commit the long-running transaction.
676     db_->CommitTransaction();
677     db_.reset();
678     // Forget the first recorded time since the database is closed.
679     first_recorded_time_ = base::Time();
680   }
681   if (thumbnail_db_) {
682     thumbnail_db_->CommitTransaction();
683     thumbnail_db_.reset();
684   }
685 }
686
687 std::pair<URLID, VisitID> HistoryBackend::AddPageVisit(
688     const GURL& url,
689     Time time,
690     VisitID referring_visit,
691     content::PageTransition transition,
692     VisitSource visit_source) {
693   // Top-level frame navigations are visible, everything else is hidden
694   bool new_hidden = !content::PageTransitionIsMainFrame(transition);
695
696   // NOTE: This code must stay in sync with
697   // ExpireHistoryBackend::ExpireURLsForVisits().
698   // TODO(pkasting): http://b/1148304 We shouldn't be marking so many URLs as
699   // typed, which would eliminate the need for this code.
700   int typed_increment = 0;
701   content::PageTransition transition_type =
702       content::PageTransitionStripQualifier(transition);
703   if ((transition_type == content::PAGE_TRANSITION_TYPED &&
704       !content::PageTransitionIsRedirect(transition)) ||
705       transition_type == content::PAGE_TRANSITION_KEYWORD_GENERATED)
706     typed_increment = 1;
707
708 #if defined(OS_ANDROID)
709   // Only count the page visit if it came from user browsing and only count it
710   // once when cycling through a redirect chain.
711   if (visit_source == SOURCE_BROWSED &&
712       (transition & content::PAGE_TRANSITION_CHAIN_END) != 0) {
713     RecordTopPageVisitStats(url);
714   }
715 #endif
716
717   // See if this URL is already in the DB.
718   URLRow url_info(url);
719   URLID url_id = db_->GetRowForURL(url, &url_info);
720   if (url_id) {
721     // Update of an existing row.
722     if (content::PageTransitionStripQualifier(transition) !=
723         content::PAGE_TRANSITION_RELOAD)
724       url_info.set_visit_count(url_info.visit_count() + 1);
725     if (typed_increment)
726       url_info.set_typed_count(url_info.typed_count() + typed_increment);
727     if (url_info.last_visit() < time)
728       url_info.set_last_visit(time);
729
730     // Only allow un-hiding of pages, never hiding.
731     if (!new_hidden)
732       url_info.set_hidden(false);
733
734     db_->UpdateURLRow(url_id, url_info);
735   } else {
736     // Addition of a new row.
737     url_info.set_visit_count(1);
738     url_info.set_typed_count(typed_increment);
739     url_info.set_last_visit(time);
740     url_info.set_hidden(new_hidden);
741
742     url_id = db_->AddURL(url_info);
743     if (!url_id) {
744       NOTREACHED() << "Adding URL failed.";
745       return std::make_pair(0, 0);
746     }
747     url_info.id_ = url_id;
748   }
749
750   // Add the visit with the time to the database.
751   VisitRow visit_info(url_id, time, referring_visit, transition, 0);
752   VisitID visit_id = db_->AddVisit(&visit_info, visit_source);
753   NotifyVisitObservers(visit_info);
754
755   if (visit_info.visit_time < first_recorded_time_)
756     first_recorded_time_ = visit_info.visit_time;
757
758   // Broadcast a notification of the visit.
759   if (visit_id) {
760     if (typed_url_syncable_service_.get())
761       typed_url_syncable_service_->OnUrlVisited(transition, &url_info);
762
763     scoped_ptr<URLVisitedDetails> details(new URLVisitedDetails);
764     details->transition = transition;
765     details->row = url_info;
766     details->visit_time = time;
767     // TODO(meelapshah) Disabled due to potential PageCycler regression.
768     // Re-enable this.
769     // GetMostRecentRedirectsTo(url, &details->redirects);
770     BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URL_VISITED,
771                            details.PassAs<HistoryDetails>());
772   } else {
773     VLOG(0) << "Failed to build visit insert statement:  "
774             << "url_id = " << url_id;
775   }
776
777   return std::make_pair(url_id, visit_id);
778 }
779
780 void HistoryBackend::AddPagesWithDetails(const URLRows& urls,
781                                          VisitSource visit_source) {
782   if (!db_)
783     return;
784
785   scoped_ptr<URLsModifiedDetails> modified(new URLsModifiedDetails);
786   for (URLRows::const_iterator i = urls.begin(); i != urls.end(); ++i) {
787     DCHECK(!i->last_visit().is_null());
788
789     // As of M37, we no longer maintain an archived database, ignore old visits.
790     if (IsExpiredVisitTime(i->last_visit()))
791       continue;
792
793     URLRow existing_url;
794     URLID url_id = db_->GetRowForURL(i->url(), &existing_url);
795     if (!url_id) {
796       // Add the page if it doesn't exist.
797       url_id = db_->AddURL(*i);
798       if (!url_id) {
799         NOTREACHED() << "Could not add row to DB";
800         return;
801       }
802
803       modified->changed_urls.push_back(*i);
804       modified->changed_urls.back().set_id(url_id);  // i->id_ is likely 0.
805     }
806
807     // Sync code manages the visits itself.
808     if (visit_source != SOURCE_SYNCED) {
809       // Make up a visit to correspond to the last visit to the page.
810       VisitRow visit_info(url_id, i->last_visit(), 0,
811                           content::PageTransitionFromInt(
812                               content::PAGE_TRANSITION_LINK |
813                               content::PAGE_TRANSITION_CHAIN_START |
814                               content::PAGE_TRANSITION_CHAIN_END), 0);
815       if (!db_->AddVisit(&visit_info, visit_source)) {
816         NOTREACHED() << "Adding visit failed.";
817         return;
818       }
819       NotifyVisitObservers(visit_info);
820
821       if (visit_info.visit_time < first_recorded_time_)
822         first_recorded_time_ = visit_info.visit_time;
823     }
824   }
825
826   if (typed_url_syncable_service_.get())
827     typed_url_syncable_service_->OnUrlsModified(&modified->changed_urls);
828
829   // Broadcast a notification for typed URLs that have been modified. This
830   // will be picked up by the in-memory URL database on the main thread.
831   //
832   // TODO(brettw) bug 1140015: Add an "add page" notification so the history
833   // views can keep in sync.
834   BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED,
835                          modified.PassAs<HistoryDetails>());
836
837   ScheduleCommit();
838 }
839
840 bool HistoryBackend::IsExpiredVisitTime(const base::Time& time) {
841   return time < expirer_.GetCurrentExpirationTime();
842 }
843
844 void HistoryBackend::SetPageTitle(const GURL& url,
845                                   const base::string16& title) {
846   if (!db_)
847     return;
848
849   // Search for recent redirects which should get the same title. We make a
850   // dummy list containing the exact URL visited if there are no redirects so
851   // the processing below can be the same.
852   history::RedirectList dummy_list;
853   history::RedirectList* redirects;
854   RedirectCache::iterator iter = recent_redirects_.Get(url);
855   if (iter != recent_redirects_.end()) {
856     redirects = &iter->second;
857
858     // This redirect chain should have the destination URL as the last item.
859     DCHECK(!redirects->empty());
860     DCHECK(redirects->back() == url);
861   } else {
862     // No redirect chain stored, make up one containing the URL we want so we
863     // can use the same logic below.
864     dummy_list.push_back(url);
865     redirects = &dummy_list;
866   }
867
868   scoped_ptr<URLsModifiedDetails> details(new URLsModifiedDetails);
869   for (size_t i = 0; i < redirects->size(); i++) {
870     URLRow row;
871     URLID row_id = db_->GetRowForURL(redirects->at(i), &row);
872     if (row_id && row.title() != title) {
873       row.set_title(title);
874       db_->UpdateURLRow(row_id, row);
875       details->changed_urls.push_back(row);
876     }
877   }
878
879   // Broadcast notifications for any URLs that have changed. This will
880   // update the in-memory database and the InMemoryURLIndex.
881   if (!details->changed_urls.empty()) {
882     if (typed_url_syncable_service_.get())
883       typed_url_syncable_service_->OnUrlsModified(&details->changed_urls);
884     BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED,
885                            details.PassAs<HistoryDetails>());
886     ScheduleCommit();
887   }
888 }
889
890 void HistoryBackend::AddPageNoVisitForBookmark(const GURL& url,
891                                                const base::string16& title) {
892   if (!db_)
893     return;
894
895   URLRow url_info(url);
896   URLID url_id = db_->GetRowForURL(url, &url_info);
897   if (url_id) {
898     // URL is already known, nothing to do.
899     return;
900   }
901
902   if (!title.empty()) {
903     url_info.set_title(title);
904   } else {
905     url_info.set_title(base::UTF8ToUTF16(url.spec()));
906   }
907
908   url_info.set_last_visit(Time::Now());
909   // Mark the page hidden. If the user types it in, it'll unhide.
910   url_info.set_hidden(true);
911
912   db_->AddURL(url_info);
913 }
914
915 void HistoryBackend::IterateURLs(
916     const scoped_refptr<visitedlink::VisitedLinkDelegate::URLEnumerator>&
917     iterator) {
918   if (db_) {
919     HistoryDatabase::URLEnumerator e;
920     if (db_->InitURLEnumeratorForEverything(&e)) {
921       URLRow info;
922       while (e.GetNextURL(&info)) {
923         iterator->OnURL(info.url());
924       }
925       iterator->OnComplete(true);  // Success.
926       return;
927     }
928   }
929   iterator->OnComplete(false);  // Failure.
930 }
931
932 bool HistoryBackend::GetAllTypedURLs(URLRows* urls) {
933   if (db_)
934     return db_->GetAllTypedUrls(urls);
935   return false;
936 }
937
938 bool HistoryBackend::GetVisitsForURL(URLID id, VisitVector* visits) {
939   if (db_)
940     return db_->GetVisitsForURL(id, visits);
941   return false;
942 }
943
944 bool HistoryBackend::GetMostRecentVisitsForURL(URLID id,
945                                                int max_visits,
946                                                VisitVector* visits) {
947   if (db_)
948     return db_->GetMostRecentVisitsForURL(id, max_visits, visits);
949   return false;
950 }
951
952 bool HistoryBackend::UpdateURL(URLID id, const history::URLRow& url) {
953   if (db_)
954     return db_->UpdateURLRow(id, url);
955   return false;
956 }
957
958 bool HistoryBackend::AddVisits(const GURL& url,
959                                const std::vector<VisitInfo>& visits,
960                                VisitSource visit_source) {
961   if (db_) {
962     for (std::vector<VisitInfo>::const_iterator visit = visits.begin();
963          visit != visits.end(); ++visit) {
964       if (!AddPageVisit(
965               url, visit->first, 0, visit->second, visit_source).first) {
966         return false;
967       }
968     }
969     ScheduleCommit();
970     return true;
971   }
972   return false;
973 }
974
975 bool HistoryBackend::RemoveVisits(const VisitVector& visits) {
976   if (!db_)
977     return false;
978
979   expirer_.ExpireVisits(visits);
980   ScheduleCommit();
981   return true;
982 }
983
984 bool HistoryBackend::GetVisitsSource(const VisitVector& visits,
985                                      VisitSourceMap* sources) {
986   if (!db_)
987     return false;
988
989   db_->GetVisitsSource(visits, sources);
990   return true;
991 }
992
993 bool HistoryBackend::GetURL(const GURL& url, history::URLRow* url_row) {
994   if (db_)
995     return db_->GetRowForURL(url, url_row) != 0;
996   return false;
997 }
998
999 HistoryBackend::QueryURLResult HistoryBackend::QueryURL(const GURL& url,
1000                                                         bool want_visits) {
1001   QueryURLResult result;
1002   result.success = db_ && db_->GetRowForURL(url, &result.row);
1003   // Optionally query the visits.
1004   if (result.success && want_visits)
1005     db_->GetVisitsForURL(result.row.id(), &result.visits);
1006   return result;
1007 }
1008
1009 TypedUrlSyncableService* HistoryBackend::GetTypedUrlSyncableService() const {
1010   return typed_url_syncable_service_.get();
1011 }
1012
1013 // Segment usage ---------------------------------------------------------------
1014
1015 void HistoryBackend::DeleteOldSegmentData() {
1016   if (db_)
1017     db_->DeleteSegmentData(Time::Now() -
1018                            TimeDelta::FromDays(kSegmentDataRetention));
1019 }
1020
1021 void HistoryBackend::QuerySegmentUsage(
1022     scoped_refptr<QuerySegmentUsageRequest> request,
1023     const Time from_time,
1024     int max_result_count) {
1025   if (request->canceled())
1026     return;
1027
1028   if (db_) {
1029     db_->QuerySegmentUsage(from_time, max_result_count, &request->value.get());
1030
1031     // If this is the first time we query segments, invoke
1032     // DeleteOldSegmentData asynchronously. We do this to cleanup old
1033     // entries.
1034     if (!segment_queried_) {
1035       segment_queried_ = true;
1036       base::MessageLoop::current()->PostTask(
1037           FROM_HERE,
1038           base::Bind(&HistoryBackend::DeleteOldSegmentData, this));
1039     }
1040   }
1041   request->ForwardResult(request->handle(), &request->value.get());
1042 }
1043
1044 // Keyword visits --------------------------------------------------------------
1045
1046 void HistoryBackend::SetKeywordSearchTermsForURL(const GURL& url,
1047                                                  TemplateURLID keyword_id,
1048                                                  const base::string16& term) {
1049   if (!db_)
1050     return;
1051
1052   // Get the ID for this URL.
1053   URLRow row;
1054   if (!db_->GetRowForURL(url, &row)) {
1055     // There is a small possibility the url was deleted before the keyword
1056     // was added. Ignore the request.
1057     return;
1058   }
1059
1060   db_->SetKeywordSearchTermsForURL(row.id(), keyword_id, term);
1061
1062   BroadcastNotifications(
1063       chrome::NOTIFICATION_HISTORY_KEYWORD_SEARCH_TERM_UPDATED,
1064       scoped_ptr<HistoryDetails>(
1065           new KeywordSearchUpdatedDetails(row, keyword_id, term)));
1066   ScheduleCommit();
1067 }
1068
1069 void HistoryBackend::DeleteAllSearchTermsForKeyword(
1070     TemplateURLID keyword_id) {
1071   if (!db_)
1072     return;
1073
1074   db_->DeleteAllSearchTermsForKeyword(keyword_id);
1075   ScheduleCommit();
1076 }
1077
1078 void HistoryBackend::GetMostRecentKeywordSearchTerms(
1079     scoped_refptr<GetMostRecentKeywordSearchTermsRequest> request,
1080     TemplateURLID keyword_id,
1081     const base::string16& prefix,
1082     int max_count) {
1083   if (request->canceled())
1084     return;
1085
1086   if (db_) {
1087     db_->GetMostRecentKeywordSearchTerms(keyword_id, prefix, max_count,
1088                                          &(request->value));
1089   }
1090   request->ForwardResult(request->handle(), &request->value);
1091 }
1092
1093 void HistoryBackend::DeleteKeywordSearchTermForURL(const GURL& url) {
1094   if (!db_)
1095     return;
1096
1097   URLID url_id = db_->GetRowForURL(url, NULL);
1098   if (!url_id)
1099     return;
1100   db_->DeleteKeywordSearchTermForURL(url_id);
1101
1102   BroadcastNotifications(
1103       chrome::NOTIFICATION_HISTORY_KEYWORD_SEARCH_TERM_DELETED,
1104       scoped_ptr<HistoryDetails>(new KeywordSearchDeletedDetails(url_id)));
1105   ScheduleCommit();
1106 }
1107
1108 void HistoryBackend::DeleteMatchingURLsForKeyword(TemplateURLID keyword_id,
1109                                                   const base::string16& term) {
1110   if (!db_)
1111     return;
1112
1113   std::vector<KeywordSearchTermRow> rows;
1114   if (db_->GetKeywordSearchTermRows(term, &rows)) {
1115     std::vector<GURL> items_to_delete;
1116     URLRow row;
1117     for (std::vector<KeywordSearchTermRow>::iterator it = rows.begin();
1118          it != rows.end(); ++it) {
1119       if ((it->keyword_id == keyword_id) && db_->GetURLRow(it->url_id, &row))
1120         items_to_delete.push_back(row.url());
1121     }
1122     DeleteURLs(items_to_delete);
1123   }
1124 }
1125
1126 // Downloads -------------------------------------------------------------------
1127
1128 uint32 HistoryBackend::GetNextDownloadId() {
1129   return db_ ? db_->GetNextDownloadId() : content::DownloadItem::kInvalidId;
1130 }
1131
1132 // Get all the download entries from the database.
1133 void HistoryBackend::QueryDownloads(std::vector<DownloadRow>* rows) {
1134   if (db_)
1135     db_->QueryDownloads(rows);
1136 }
1137
1138 // Update a particular download entry.
1139 void HistoryBackend::UpdateDownload(const history::DownloadRow& data) {
1140   if (!db_)
1141     return;
1142   db_->UpdateDownload(data);
1143   ScheduleCommit();
1144 }
1145
1146 bool HistoryBackend::CreateDownload(const history::DownloadRow& history_info) {
1147   if (!db_)
1148     return false;
1149   bool success = db_->CreateDownload(history_info);
1150   ScheduleCommit();
1151   return success;
1152 }
1153
1154 void HistoryBackend::RemoveDownloads(const std::set<uint32>& ids) {
1155   if (!db_)
1156     return;
1157   size_t downloads_count_before = db_->CountDownloads();
1158   base::TimeTicks started_removing = base::TimeTicks::Now();
1159   // HistoryBackend uses a long-running Transaction that is committed
1160   // periodically, so this loop doesn't actually hit the disk too hard.
1161   for (std::set<uint32>::const_iterator it = ids.begin();
1162        it != ids.end(); ++it) {
1163     db_->RemoveDownload(*it);
1164   }
1165   ScheduleCommit();
1166   base::TimeTicks finished_removing = base::TimeTicks::Now();
1167   size_t downloads_count_after = db_->CountDownloads();
1168
1169   DCHECK_LE(downloads_count_after, downloads_count_before);
1170   if (downloads_count_after > downloads_count_before)
1171     return;
1172   size_t num_downloads_deleted = downloads_count_before - downloads_count_after;
1173   UMA_HISTOGRAM_COUNTS("Download.DatabaseRemoveDownloadsCount",
1174                         num_downloads_deleted);
1175   base::TimeDelta micros = (1000 * (finished_removing - started_removing));
1176   UMA_HISTOGRAM_TIMES("Download.DatabaseRemoveDownloadsTime", micros);
1177   if (num_downloads_deleted > 0) {
1178     UMA_HISTOGRAM_TIMES("Download.DatabaseRemoveDownloadsTimePerRecord",
1179                         (1000 * micros) / num_downloads_deleted);
1180   }
1181   DCHECK_GE(ids.size(), num_downloads_deleted);
1182   if (ids.size() < num_downloads_deleted)
1183     return;
1184   UMA_HISTOGRAM_COUNTS("Download.DatabaseRemoveDownloadsCountNotRemoved",
1185                         ids.size() - num_downloads_deleted);
1186 }
1187
1188 void HistoryBackend::QueryHistory(scoped_refptr<QueryHistoryRequest> request,
1189                                   const base::string16& text_query,
1190                                   const QueryOptions& options) {
1191   if (request->canceled())
1192     return;
1193
1194   TimeTicks beginning_time = TimeTicks::Now();
1195
1196   if (db_) {
1197     if (text_query.empty()) {
1198       // Basic history query for the main database.
1199       QueryHistoryBasic(options, &request->value);
1200     } else {
1201       // Text history query.
1202       QueryHistoryText(text_query, options, &request->value);
1203     }
1204   }
1205
1206   request->ForwardResult(request->handle(), &request->value);
1207
1208   UMA_HISTOGRAM_TIMES("History.QueryHistory",
1209                       TimeTicks::Now() - beginning_time);
1210 }
1211
1212 // Basic time-based querying of history.
1213 void HistoryBackend::QueryHistoryBasic(const QueryOptions& options,
1214                                        QueryResults* result) {
1215   // First get all visits.
1216   VisitVector visits;
1217   bool has_more_results = db_->GetVisibleVisitsInRange(options, &visits);
1218   DCHECK(static_cast<int>(visits.size()) <= options.EffectiveMaxCount());
1219
1220   // Now add them and the URL rows to the results.
1221   URLResult url_result;
1222   for (size_t i = 0; i < visits.size(); i++) {
1223     const VisitRow visit = visits[i];
1224
1225     // Add a result row for this visit, get the URL info from the DB.
1226     if (!db_->GetURLRow(visit.url_id, &url_result)) {
1227       VLOG(0) << "Failed to get id " << visit.url_id
1228               << " from history.urls.";
1229       continue;  // DB out of sync and URL doesn't exist, try to recover.
1230     }
1231
1232     if (!url_result.url().is_valid()) {
1233       VLOG(0) << "Got invalid URL from history.urls with id "
1234               << visit.url_id << ":  "
1235               << url_result.url().possibly_invalid_spec();
1236       continue;  // Don't report invalid URLs in case of corruption.
1237     }
1238
1239     url_result.set_visit_time(visit.visit_time);
1240
1241     // Set whether the visit was blocked for a managed user by looking at the
1242     // transition type.
1243     url_result.set_blocked_visit(
1244         (visit.transition & content::PAGE_TRANSITION_BLOCKED) != 0);
1245
1246     // We don't set any of the query-specific parts of the URLResult, since
1247     // snippets and stuff don't apply to basic querying.
1248     result->AppendURLBySwapping(&url_result);
1249   }
1250
1251   if (!has_more_results && options.begin_time <= first_recorded_time_)
1252     result->set_reached_beginning(true);
1253 }
1254
1255 // Text-based querying of history.
1256 void HistoryBackend::QueryHistoryText(const base::string16& text_query,
1257                                       const QueryOptions& options,
1258                                       QueryResults* result) {
1259   URLRows text_matches;
1260   db_->GetTextMatches(text_query, &text_matches);
1261
1262   std::vector<URLResult> matching_visits;
1263   VisitVector visits;    // Declare outside loop to prevent re-construction.
1264   for (size_t i = 0; i < text_matches.size(); i++) {
1265     const URLRow& text_match = text_matches[i];
1266     // Get all visits for given URL match.
1267     db_->GetVisibleVisitsForURL(text_match.id(), options, &visits);
1268     for (size_t j = 0; j < visits.size(); j++) {
1269       URLResult url_result(text_match);
1270       url_result.set_visit_time(visits[j].visit_time);
1271       matching_visits.push_back(url_result);
1272     }
1273   }
1274
1275   std::sort(matching_visits.begin(), matching_visits.end(),
1276             URLResult::CompareVisitTime);
1277
1278   size_t max_results = options.max_count == 0 ?
1279       std::numeric_limits<size_t>::max() : static_cast<int>(options.max_count);
1280   for (std::vector<URLResult>::iterator it = matching_visits.begin();
1281        it != matching_visits.end() && result->size() < max_results; ++it) {
1282     result->AppendURLBySwapping(&(*it));
1283   }
1284
1285   if (matching_visits.size() == result->size() &&
1286       options.begin_time <= first_recorded_time_)
1287     result->set_reached_beginning(true);
1288 }
1289
1290 // Frontend to GetMostRecentRedirectsFrom from the history thread.
1291 void HistoryBackend::QueryRedirectsFrom(
1292     scoped_refptr<QueryRedirectsRequest> request,
1293     const GURL& url) {
1294   if (request->canceled())
1295     return;
1296   bool success = GetMostRecentRedirectsFrom(url, &request->value);
1297   request->ForwardResult(request->handle(), url, success, &request->value);
1298 }
1299
1300 void HistoryBackend::QueryRedirectsTo(
1301     scoped_refptr<QueryRedirectsRequest> request,
1302     const GURL& url) {
1303   if (request->canceled())
1304     return;
1305   bool success = GetMostRecentRedirectsTo(url, &request->value);
1306   request->ForwardResult(request->handle(), url, success, &request->value);
1307 }
1308
1309 void HistoryBackend::GetVisibleVisitCountToHost(
1310     scoped_refptr<GetVisibleVisitCountToHostRequest> request,
1311     const GURL& url) {
1312   if (request->canceled())
1313     return;
1314   int count = 0;
1315   Time first_visit;
1316   const bool success = db_.get() &&
1317       db_->GetVisibleVisitCountToHost(url, &count, &first_visit);
1318   request->ForwardResult(request->handle(), success, count, first_visit);
1319 }
1320
1321 void HistoryBackend::QueryTopURLsAndRedirects(
1322     scoped_refptr<QueryTopURLsAndRedirectsRequest> request,
1323     int result_count) {
1324   if (request->canceled())
1325     return;
1326
1327   if (!db_) {
1328     request->ForwardResult(request->handle(), false, NULL, NULL);
1329     return;
1330   }
1331
1332   std::vector<GURL>* top_urls = &request->value.a;
1333   history::RedirectMap* redirects = &request->value.b;
1334
1335   ScopedVector<PageUsageData> data;
1336   db_->QuerySegmentUsage(base::Time::Now() - base::TimeDelta::FromDays(90),
1337       result_count, &data.get());
1338
1339   for (size_t i = 0; i < data.size(); ++i) {
1340     top_urls->push_back(data[i]->GetURL());
1341     RefCountedVector<GURL>* list = new RefCountedVector<GURL>;
1342     GetMostRecentRedirectsFrom(top_urls->back(), &list->data);
1343     (*redirects)[top_urls->back()] = list;
1344   }
1345
1346   request->ForwardResult(request->handle(), true, top_urls, redirects);
1347 }
1348
1349 // Will replace QueryTopURLsAndRedirectsRequest.
1350 void HistoryBackend::QueryMostVisitedURLs(
1351     scoped_refptr<QueryMostVisitedURLsRequest> request,
1352     int result_count,
1353     int days_back) {
1354   if (request->canceled())
1355     return;
1356
1357   if (!db_) {
1358     // No History Database - return an empty list.
1359     request->ForwardResult(request->handle(), MostVisitedURLList());
1360     return;
1361   }
1362
1363   MostVisitedURLList* result = &request->value;
1364   QueryMostVisitedURLsImpl(result_count, days_back, result);
1365   request->ForwardResult(request->handle(), *result);
1366 }
1367
1368 void HistoryBackend::QueryFilteredURLs(
1369       scoped_refptr<QueryFilteredURLsRequest> request,
1370       int result_count,
1371       const history::VisitFilter& filter,
1372       bool extended_info)  {
1373   if (request->canceled())
1374     return;
1375
1376   base::Time request_start = base::Time::Now();
1377
1378   if (!db_) {
1379     // No History Database - return an empty list.
1380     request->ForwardResult(request->handle(), FilteredURLList());
1381     return;
1382   }
1383
1384   VisitVector visits;
1385   db_->GetDirectVisitsDuringTimes(filter, 0, &visits);
1386
1387   std::map<URLID, double> score_map;
1388   for (size_t i = 0; i < visits.size(); ++i) {
1389     score_map[visits[i].url_id] += filter.GetVisitScore(visits[i]);
1390   }
1391
1392   // TODO(georgey): experiment with visit_segment database granularity (it is
1393   // currently 24 hours) to use it directly instead of using visits database,
1394   // which is considerably slower.
1395   ScopedVector<PageUsageData> data;
1396   data.reserve(score_map.size());
1397   for (std::map<URLID, double>::iterator it = score_map.begin();
1398        it != score_map.end(); ++it) {
1399     PageUsageData* pud = new PageUsageData(it->first);
1400     pud->SetScore(it->second);
1401     data.push_back(pud);
1402   }
1403
1404   // Limit to the top |result_count| results.
1405   std::sort(data.begin(), data.end(), PageUsageData::Predicate);
1406   if (result_count && implicit_cast<int>(data.size()) > result_count)
1407     data.resize(result_count);
1408
1409   for (size_t i = 0; i < data.size(); ++i) {
1410     URLRow info;
1411     if (db_->GetURLRow(data[i]->GetID(), &info)) {
1412       data[i]->SetURL(info.url());
1413       data[i]->SetTitle(info.title());
1414     }
1415   }
1416
1417   FilteredURLList& result = request->value;
1418   for (size_t i = 0; i < data.size(); ++i) {
1419     PageUsageData* current_data = data[i];
1420     FilteredURL url(*current_data);
1421
1422     if (extended_info) {
1423       VisitVector visits;
1424       db_->GetVisitsForURL(current_data->GetID(), &visits);
1425       if (visits.size() > 0) {
1426         url.extended_info.total_visits = visits.size();
1427         for (size_t i = 0; i < visits.size(); ++i) {
1428           url.extended_info.duration_opened +=
1429               visits[i].visit_duration.InSeconds();
1430           if (visits[i].visit_time > url.extended_info.last_visit_time) {
1431             url.extended_info.last_visit_time = visits[i].visit_time;
1432           }
1433         }
1434         // TODO(macourteau): implement the url.extended_info.visits stat.
1435       }
1436     }
1437     result.push_back(url);
1438   }
1439
1440   int delta_time = std::max(1, std::min(999,
1441       static_cast<int>((base::Time::Now() - request_start).InMilliseconds())));
1442   STATIC_HISTOGRAM_POINTER_BLOCK(
1443       "NewTabPage.SuggestedSitesLoadTime",
1444       Add(delta_time),
1445       base::LinearHistogram::FactoryGet("NewTabPage.SuggestedSitesLoadTime",
1446           1, 1000, 100, base::Histogram::kUmaTargetedHistogramFlag));
1447
1448   request->ForwardResult(request->handle(), result);
1449 }
1450
1451 void HistoryBackend::QueryMostVisitedURLsImpl(int result_count,
1452                                               int days_back,
1453                                               MostVisitedURLList* result) {
1454   if (!db_)
1455     return;
1456
1457   ScopedVector<PageUsageData> data;
1458   db_->QuerySegmentUsage(base::Time::Now() -
1459                          base::TimeDelta::FromDays(days_back),
1460                          result_count, &data.get());
1461
1462   for (size_t i = 0; i < data.size(); ++i) {
1463     PageUsageData* current_data = data[i];
1464     RedirectList redirects;
1465     GetMostRecentRedirectsFrom(current_data->GetURL(), &redirects);
1466     MostVisitedURL url = MakeMostVisitedURL(*current_data, redirects);
1467     result->push_back(url);
1468   }
1469 }
1470
1471 void HistoryBackend::GetRedirectsFromSpecificVisit(
1472     VisitID cur_visit, history::RedirectList* redirects) {
1473   // Follow any redirects from the given visit and add them to the list.
1474   // It *should* be impossible to get a circular chain here, but we check
1475   // just in case to avoid infinite loops.
1476   GURL cur_url;
1477   std::set<VisitID> visit_set;
1478   visit_set.insert(cur_visit);
1479   while (db_->GetRedirectFromVisit(cur_visit, &cur_visit, &cur_url)) {
1480     if (visit_set.find(cur_visit) != visit_set.end()) {
1481       NOTREACHED() << "Loop in visit chain, giving up";
1482       return;
1483     }
1484     visit_set.insert(cur_visit);
1485     redirects->push_back(cur_url);
1486   }
1487 }
1488
1489 void HistoryBackend::GetRedirectsToSpecificVisit(
1490     VisitID cur_visit,
1491     history::RedirectList* redirects) {
1492   // Follow redirects going to cur_visit. These are added to |redirects| in
1493   // the order they are found. If a redirect chain looks like A -> B -> C and
1494   // |cur_visit| = C, redirects will be {B, A} in that order.
1495   if (!db_)
1496     return;
1497
1498   GURL cur_url;
1499   std::set<VisitID> visit_set;
1500   visit_set.insert(cur_visit);
1501   while (db_->GetRedirectToVisit(cur_visit, &cur_visit, &cur_url)) {
1502     if (visit_set.find(cur_visit) != visit_set.end()) {
1503       NOTREACHED() << "Loop in visit chain, giving up";
1504       return;
1505     }
1506     visit_set.insert(cur_visit);
1507     redirects->push_back(cur_url);
1508   }
1509 }
1510
1511 bool HistoryBackend::GetMostRecentRedirectsFrom(
1512     const GURL& from_url,
1513     history::RedirectList* redirects) {
1514   redirects->clear();
1515   if (!db_)
1516     return false;
1517
1518   URLID from_url_id = db_->GetRowForURL(from_url, NULL);
1519   VisitID cur_visit = db_->GetMostRecentVisitForURL(from_url_id, NULL);
1520   if (!cur_visit)
1521     return false;  // No visits for URL.
1522
1523   GetRedirectsFromSpecificVisit(cur_visit, redirects);
1524   return true;
1525 }
1526
1527 bool HistoryBackend::GetMostRecentRedirectsTo(
1528     const GURL& to_url,
1529     history::RedirectList* redirects) {
1530   redirects->clear();
1531   if (!db_)
1532     return false;
1533
1534   URLID to_url_id = db_->GetRowForURL(to_url, NULL);
1535   VisitID cur_visit = db_->GetMostRecentVisitForURL(to_url_id, NULL);
1536   if (!cur_visit)
1537     return false;  // No visits for URL.
1538
1539   GetRedirectsToSpecificVisit(cur_visit, redirects);
1540   return true;
1541 }
1542
1543 void HistoryBackend::ScheduleAutocomplete(HistoryURLProvider* provider,
1544                                           HistoryURLProviderParams* params) {
1545   // ExecuteWithDB should handle the NULL database case.
1546   provider->ExecuteWithDB(this, db_.get(), params);
1547 }
1548
1549 void HistoryBackend::DeleteFTSIndexDatabases() {
1550   // Find files on disk matching the text databases file pattern so we can
1551   // quickly test for and delete them.
1552   base::FilePath::StringType filepattern =
1553       FILE_PATH_LITERAL("History Index *");
1554   base::FileEnumerator enumerator(
1555       history_dir_, false, base::FileEnumerator::FILES, filepattern);
1556   int num_databases_deleted = 0;
1557   base::FilePath current_file;
1558   while (!(current_file = enumerator.Next()).empty()) {
1559     if (sql::Connection::Delete(current_file))
1560       num_databases_deleted++;
1561   }
1562   UMA_HISTOGRAM_COUNTS("History.DeleteFTSIndexDatabases",
1563                        num_databases_deleted);
1564 }
1565
1566 void HistoryBackend::GetFavicons(
1567     const std::vector<GURL>& icon_urls,
1568     int icon_types,
1569     const std::vector<int>& desired_sizes,
1570     std::vector<favicon_base::FaviconRawBitmapResult>* bitmap_results) {
1571   UpdateFaviconMappingsAndFetchImpl(NULL, icon_urls, icon_types, desired_sizes,
1572                                     bitmap_results);
1573 }
1574
1575 void HistoryBackend::GetLargestFaviconForURL(
1576     const GURL& page_url,
1577     const std::vector<int>& icon_types,
1578     int minimum_size_in_pixels,
1579     favicon_base::FaviconRawBitmapResult* favicon_bitmap_result) {
1580   DCHECK(favicon_bitmap_result);
1581
1582   if (!db_ || !thumbnail_db_)
1583     return;
1584
1585   TimeTicks beginning_time = TimeTicks::Now();
1586
1587   std::vector<IconMapping> icon_mappings;
1588   if (!thumbnail_db_->GetIconMappingsForPageURL(page_url, &icon_mappings) ||
1589       icon_mappings.empty())
1590     return;
1591
1592   int required_icon_types = 0;
1593   for (std::vector<int>::const_iterator i = icon_types.begin();
1594        i != icon_types.end(); ++i) {
1595     required_icon_types |= *i;
1596   }
1597
1598   // Find the largest bitmap for each IconType placing in
1599   // |largest_favicon_bitmaps|.
1600   std::map<favicon_base::IconType, FaviconBitmap> largest_favicon_bitmaps;
1601   for (std::vector<IconMapping>::const_iterator i = icon_mappings.begin();
1602        i != icon_mappings.end(); ++i) {
1603     if (!(i->icon_type & required_icon_types))
1604       continue;
1605     std::vector<FaviconBitmapIDSize> bitmap_id_sizes;
1606     thumbnail_db_->GetFaviconBitmapIDSizes(i->icon_id, &bitmap_id_sizes);
1607     FaviconBitmap& largest = largest_favicon_bitmaps[i->icon_type];
1608     for (std::vector<FaviconBitmapIDSize>::const_iterator j =
1609              bitmap_id_sizes.begin(); j != bitmap_id_sizes.end(); ++j) {
1610       if (largest.bitmap_id == 0 ||
1611           (largest.pixel_size.width() < j->pixel_size.width() &&
1612            largest.pixel_size.height() < j->pixel_size.height())) {
1613         largest.icon_id = i->icon_id;
1614         largest.bitmap_id = j->bitmap_id;
1615         largest.pixel_size = j->pixel_size;
1616       }
1617     }
1618   }
1619   if (largest_favicon_bitmaps.empty())
1620     return;
1621
1622   // Find an icon which is larger than minimum_size_in_pixels in the order of
1623   // icon_types.
1624   FaviconBitmap largest_icon;
1625   for (std::vector<int>::const_iterator t = icon_types.begin();
1626        t != icon_types.end(); ++t) {
1627     for (std::map<favicon_base::IconType, FaviconBitmap>::const_iterator f =
1628              largest_favicon_bitmaps.begin();
1629          f != largest_favicon_bitmaps.end();
1630          ++f) {
1631       if (f->first & *t &&
1632           (largest_icon.bitmap_id == 0 ||
1633            (largest_icon.pixel_size.height() < f->second.pixel_size.height() &&
1634             largest_icon.pixel_size.width() < f->second.pixel_size.width()))) {
1635         largest_icon = f->second;
1636       }
1637     }
1638     if (largest_icon.pixel_size.width() > minimum_size_in_pixels &&
1639         largest_icon.pixel_size.height() > minimum_size_in_pixels)
1640       break;
1641   }
1642
1643   GURL icon_url;
1644   favicon_base::IconType icon_type;
1645   if (!thumbnail_db_->GetFaviconHeader(largest_icon.icon_id, &icon_url,
1646                                        &icon_type)) {
1647     return;
1648   }
1649
1650   base::Time last_updated;
1651   favicon_base::FaviconRawBitmapResult bitmap_result;
1652   bitmap_result.icon_url = icon_url;
1653   bitmap_result.icon_type = icon_type;
1654   if (!thumbnail_db_->GetFaviconBitmap(largest_icon.bitmap_id,
1655                                        &last_updated,
1656                                        &bitmap_result.bitmap_data,
1657                                        &bitmap_result.pixel_size)) {
1658     return;
1659   }
1660
1661   bitmap_result.expired = (Time::Now() - last_updated) >
1662       TimeDelta::FromDays(kFaviconRefetchDays);
1663   if (bitmap_result.is_valid())
1664     *favicon_bitmap_result = bitmap_result;
1665
1666   HISTOGRAM_TIMES("History.GetLargestFaviconForURL",
1667                   TimeTicks::Now() - beginning_time);
1668 }
1669
1670 void HistoryBackend::GetFaviconsForURL(
1671     const GURL& page_url,
1672     int icon_types,
1673     const std::vector<int>& desired_sizes,
1674     std::vector<favicon_base::FaviconRawBitmapResult>* bitmap_results) {
1675   DCHECK(bitmap_results);
1676   GetFaviconsFromDB(page_url, icon_types, desired_sizes, bitmap_results);
1677 }
1678
1679 void HistoryBackend::GetFaviconForID(
1680     favicon_base::FaviconID favicon_id,
1681     int desired_size,
1682     std::vector<favicon_base::FaviconRawBitmapResult>* bitmap_results) {
1683   std::vector<favicon_base::FaviconID> favicon_ids;
1684   favicon_ids.push_back(favicon_id);
1685   std::vector<int> desired_sizes;
1686   desired_sizes.push_back(desired_size);
1687
1688   // Get results from DB.
1689   GetFaviconBitmapResultsForBestMatch(favicon_ids,
1690                                       desired_sizes,
1691                                       bitmap_results);
1692 }
1693
1694 void HistoryBackend::UpdateFaviconMappingsAndFetch(
1695     const GURL& page_url,
1696     const std::vector<GURL>& icon_urls,
1697     int icon_types,
1698     const std::vector<int>& desired_sizes,
1699     std::vector<favicon_base::FaviconRawBitmapResult>* bitmap_results) {
1700   UpdateFaviconMappingsAndFetchImpl(&page_url, icon_urls, icon_types,
1701                                     desired_sizes, bitmap_results);
1702 }
1703
1704 void HistoryBackend::MergeFavicon(
1705     const GURL& page_url,
1706     const GURL& icon_url,
1707     favicon_base::IconType icon_type,
1708     scoped_refptr<base::RefCountedMemory> bitmap_data,
1709     const gfx::Size& pixel_size) {
1710   if (!thumbnail_db_ || !db_)
1711     return;
1712
1713   favicon_base::FaviconID favicon_id =
1714       thumbnail_db_->GetFaviconIDForFaviconURL(icon_url, icon_type, NULL);
1715
1716   if (!favicon_id) {
1717     // There is no favicon at |icon_url|, create it.
1718     favicon_id = thumbnail_db_->AddFavicon(icon_url, icon_type);
1719   }
1720
1721   std::vector<FaviconBitmapIDSize> bitmap_id_sizes;
1722   thumbnail_db_->GetFaviconBitmapIDSizes(favicon_id, &bitmap_id_sizes);
1723
1724   // If there is already a favicon bitmap of |pixel_size| at |icon_url|,
1725   // replace it.
1726   bool bitmap_identical = false;
1727   bool replaced_bitmap = false;
1728   for (size_t i = 0; i < bitmap_id_sizes.size(); ++i) {
1729     if (bitmap_id_sizes[i].pixel_size == pixel_size) {
1730       if (IsFaviconBitmapDataEqual(bitmap_id_sizes[i].bitmap_id, bitmap_data)) {
1731         thumbnail_db_->SetFaviconBitmapLastUpdateTime(
1732             bitmap_id_sizes[i].bitmap_id, base::Time::Now());
1733         bitmap_identical = true;
1734       } else {
1735         thumbnail_db_->SetFaviconBitmap(bitmap_id_sizes[i].bitmap_id,
1736             bitmap_data, base::Time::Now());
1737         replaced_bitmap = true;
1738       }
1739       break;
1740     }
1741   }
1742
1743   // Create a vector of the pixel sizes of the favicon bitmaps currently at
1744   // |icon_url|.
1745   std::vector<gfx::Size> favicon_sizes;
1746   for (size_t i = 0; i < bitmap_id_sizes.size(); ++i)
1747     favicon_sizes.push_back(bitmap_id_sizes[i].pixel_size);
1748
1749   if (!replaced_bitmap && !bitmap_identical) {
1750     // Set the preexisting favicon bitmaps as expired as the preexisting favicon
1751     // bitmaps are not consistent with the merged in data.
1752     thumbnail_db_->SetFaviconOutOfDate(favicon_id);
1753
1754     // Delete an arbitrary favicon bitmap to avoid going over the limit of
1755     // |kMaxFaviconBitmapsPerIconURL|.
1756     if (bitmap_id_sizes.size() >= kMaxFaviconBitmapsPerIconURL) {
1757       thumbnail_db_->DeleteFaviconBitmap(bitmap_id_sizes[0].bitmap_id);
1758       favicon_sizes.erase(favicon_sizes.begin());
1759     }
1760     thumbnail_db_->AddFaviconBitmap(favicon_id, bitmap_data, base::Time::Now(),
1761                                     pixel_size);
1762     favicon_sizes.push_back(pixel_size);
1763   }
1764
1765   // A site may have changed the favicons that it uses for |page_url|.
1766   // Example Scenario:
1767   //   page_url = news.google.com
1768   //   Initial State: www.google.com/favicon.ico 16x16, 32x32
1769   //   MergeFavicon(news.google.com, news.google.com/news_specific.ico, ...,
1770   //                ..., 16x16)
1771   //
1772   // Difficulties:
1773   // 1. Sync requires that a call to GetFaviconsForURL() returns the
1774   //    |bitmap_data| passed into MergeFavicon().
1775   //    - It is invalid for the 16x16 bitmap for www.google.com/favicon.ico to
1776   //      stay mapped to news.google.com because it would be unclear which 16x16
1777   //      bitmap should be returned via GetFaviconsForURL().
1778   //
1779   // 2. www.google.com/favicon.ico may be mapped to more than just
1780   //    news.google.com (eg www.google.com).
1781   //    - The 16x16 bitmap cannot be deleted from www.google.com/favicon.ico
1782   //
1783   // To resolve these problems, we copy all of the favicon bitmaps previously
1784   // mapped to news.google.com (|page_url|) and add them to the favicon at
1785   // news.google.com/news_specific.ico (|icon_url|). The favicon sizes for
1786   // |icon_url| are set to default to indicate that |icon_url| has incomplete
1787   // / incorrect data.
1788   // Difficulty 1: All but news.google.com/news_specific.ico are unmapped from
1789   //              news.google.com
1790   // Difficulty 2: The favicon bitmaps for www.google.com/favicon.ico are not
1791   //               modified.
1792
1793   std::vector<IconMapping> icon_mappings;
1794   thumbnail_db_->GetIconMappingsForPageURL(page_url, icon_type, &icon_mappings);
1795
1796   // Copy the favicon bitmaps mapped to |page_url| to the favicon at |icon_url|
1797   // till the limit of |kMaxFaviconBitmapsPerIconURL| is reached.
1798   for (size_t i = 0; i < icon_mappings.size(); ++i) {
1799     if (favicon_sizes.size() >= kMaxFaviconBitmapsPerIconURL)
1800       break;
1801
1802     if (icon_mappings[i].icon_url == icon_url)
1803       continue;
1804
1805     std::vector<FaviconBitmap> bitmaps_to_copy;
1806     thumbnail_db_->GetFaviconBitmaps(icon_mappings[i].icon_id,
1807                                      &bitmaps_to_copy);
1808     for (size_t j = 0; j < bitmaps_to_copy.size(); ++j) {
1809       // Do not add a favicon bitmap at a pixel size for which there is already
1810       // a favicon bitmap mapped to |icon_url|. The one there is more correct
1811       // and having multiple equally sized favicon bitmaps for |page_url| is
1812       // ambiguous in terms of GetFaviconsForURL().
1813       std::vector<gfx::Size>::iterator it = std::find(favicon_sizes.begin(),
1814           favicon_sizes.end(), bitmaps_to_copy[j].pixel_size);
1815       if (it != favicon_sizes.end())
1816         continue;
1817
1818       // Add the favicon bitmap as expired as it is not consistent with the
1819       // merged in data.
1820       thumbnail_db_->AddFaviconBitmap(favicon_id,
1821           bitmaps_to_copy[j].bitmap_data, base::Time(),
1822           bitmaps_to_copy[j].pixel_size);
1823       favicon_sizes.push_back(bitmaps_to_copy[j].pixel_size);
1824
1825       if (favicon_sizes.size() >= kMaxFaviconBitmapsPerIconURL)
1826         break;
1827     }
1828   }
1829
1830   // Update the favicon mappings such that only |icon_url| is mapped to
1831   // |page_url|.
1832   bool mapping_changed = false;
1833   if (icon_mappings.size() != 1 || icon_mappings[0].icon_url != icon_url) {
1834     std::vector<favicon_base::FaviconID> favicon_ids;
1835     favicon_ids.push_back(favicon_id);
1836     SetFaviconMappingsForPageAndRedirects(page_url, icon_type, favicon_ids);
1837     mapping_changed = true;
1838   }
1839
1840   if (mapping_changed || !bitmap_identical)
1841     SendFaviconChangedNotificationForPageAndRedirects(page_url);
1842   ScheduleCommit();
1843 }
1844
1845 void HistoryBackend::SetFavicons(
1846     const GURL& page_url,
1847     favicon_base::IconType icon_type,
1848     const std::vector<favicon_base::FaviconRawBitmapData>&
1849         favicon_bitmap_data) {
1850   if (!thumbnail_db_ || !db_)
1851     return;
1852
1853   DCHECK(ValidateSetFaviconsParams(favicon_bitmap_data));
1854
1855   // Build map of FaviconRawBitmapData for each icon url.
1856   typedef std::map<GURL, std::vector<favicon_base::FaviconRawBitmapData> >
1857       BitmapDataByIconURL;
1858   BitmapDataByIconURL grouped_by_icon_url;
1859   for (size_t i = 0; i < favicon_bitmap_data.size(); ++i) {
1860     const GURL& icon_url = favicon_bitmap_data[i].icon_url;
1861     grouped_by_icon_url[icon_url].push_back(favicon_bitmap_data[i]);
1862   }
1863
1864   // Track whether the method modifies or creates any favicon bitmaps, favicons
1865   // or icon mappings.
1866   bool data_modified = false;
1867
1868   std::vector<favicon_base::FaviconID> icon_ids;
1869   for (BitmapDataByIconURL::const_iterator it = grouped_by_icon_url.begin();
1870        it != grouped_by_icon_url.end(); ++it) {
1871     const GURL& icon_url = it->first;
1872     favicon_base::FaviconID icon_id =
1873         thumbnail_db_->GetFaviconIDForFaviconURL(icon_url, icon_type, NULL);
1874
1875     if (!icon_id) {
1876       // TODO(pkotwicz): Remove the favicon sizes attribute from
1877       // ThumbnailDatabase::AddFavicon().
1878       icon_id = thumbnail_db_->AddFavicon(icon_url, icon_type);
1879       data_modified = true;
1880     }
1881     icon_ids.push_back(icon_id);
1882
1883     if (!data_modified)
1884       SetFaviconBitmaps(icon_id, it->second, &data_modified);
1885     else
1886       SetFaviconBitmaps(icon_id, it->second, NULL);
1887   }
1888
1889   data_modified |=
1890     SetFaviconMappingsForPageAndRedirects(page_url, icon_type, icon_ids);
1891
1892   if (data_modified) {
1893     // Send notification to the UI as an icon mapping, favicon, or favicon
1894     // bitmap was changed by this function.
1895     SendFaviconChangedNotificationForPageAndRedirects(page_url);
1896   }
1897   ScheduleCommit();
1898 }
1899
1900 void HistoryBackend::SetFaviconsOutOfDateForPage(const GURL& page_url) {
1901   std::vector<IconMapping> icon_mappings;
1902
1903   if (!thumbnail_db_ ||
1904       !thumbnail_db_->GetIconMappingsForPageURL(page_url,
1905                                                 &icon_mappings))
1906     return;
1907
1908   for (std::vector<IconMapping>::iterator m = icon_mappings.begin();
1909        m != icon_mappings.end(); ++m) {
1910     thumbnail_db_->SetFaviconOutOfDate(m->icon_id);
1911   }
1912   ScheduleCommit();
1913 }
1914
1915 void HistoryBackend::CloneFavicons(const GURL& old_page_url,
1916                                    const GURL& new_page_url) {
1917   if (!thumbnail_db_)
1918     return;
1919
1920   // Prevent cross-domain cloning.
1921   if (old_page_url.GetOrigin() != new_page_url.GetOrigin())
1922     return;
1923
1924   thumbnail_db_->CloneIconMappings(old_page_url, new_page_url);
1925   ScheduleCommit();
1926 }
1927
1928 void HistoryBackend::SetImportedFavicons(
1929     const std::vector<ImportedFaviconUsage>& favicon_usage) {
1930   if (!db_ || !thumbnail_db_)
1931     return;
1932
1933   Time now = Time::Now();
1934
1935   // Track all URLs that had their favicons set or updated.
1936   std::set<GURL> favicons_changed;
1937
1938   for (size_t i = 0; i < favicon_usage.size(); i++) {
1939     favicon_base::FaviconID favicon_id =
1940         thumbnail_db_->GetFaviconIDForFaviconURL(
1941             favicon_usage[i].favicon_url, favicon_base::FAVICON, NULL);
1942     if (!favicon_id) {
1943       // This favicon doesn't exist yet, so we create it using the given data.
1944       // TODO(pkotwicz): Pass in real pixel size.
1945       favicon_id = thumbnail_db_->AddFavicon(
1946           favicon_usage[i].favicon_url,
1947           favicon_base::FAVICON,
1948           new base::RefCountedBytes(favicon_usage[i].png_data),
1949           now,
1950           gfx::Size());
1951     }
1952
1953     // Save the mapping from all the URLs to the favicon.
1954     HistoryClient* history_client = GetHistoryClient();
1955     for (std::set<GURL>::const_iterator url = favicon_usage[i].urls.begin();
1956          url != favicon_usage[i].urls.end(); ++url) {
1957       URLRow url_row;
1958       if (!db_->GetRowForURL(*url, &url_row)) {
1959         // If the URL is present as a bookmark, add the url in history to
1960         // save the favicon mapping. This will match with what history db does
1961         // for regular bookmarked URLs with favicons - when history db is
1962         // cleaned, we keep an entry in the db with 0 visits as long as that
1963         // url is bookmarked.
1964         if (history_client && history_client->IsBookmarked(*url)) {
1965           URLRow url_info(*url);
1966           url_info.set_visit_count(0);
1967           url_info.set_typed_count(0);
1968           url_info.set_last_visit(base::Time());
1969           url_info.set_hidden(false);
1970           db_->AddURL(url_info);
1971           thumbnail_db_->AddIconMapping(*url, favicon_id);
1972           favicons_changed.insert(*url);
1973         }
1974       } else {
1975         if (!thumbnail_db_->GetIconMappingsForPageURL(
1976                 *url, favicon_base::FAVICON, NULL)) {
1977           // URL is present in history, update the favicon *only* if it is not
1978           // set already.
1979           thumbnail_db_->AddIconMapping(*url, favicon_id);
1980           favicons_changed.insert(*url);
1981         }
1982       }
1983     }
1984   }
1985
1986   if (!favicons_changed.empty()) {
1987     // Send the notification about the changed favicon URLs.
1988     scoped_ptr<FaviconChangedDetails> changed_details(
1989         new FaviconChangedDetails);
1990     changed_details->urls.swap(favicons_changed);
1991     BroadcastNotifications(chrome::NOTIFICATION_FAVICON_CHANGED,
1992                            changed_details.PassAs<HistoryDetails>());
1993   }
1994 }
1995
1996 void HistoryBackend::UpdateFaviconMappingsAndFetchImpl(
1997     const GURL* page_url,
1998     const std::vector<GURL>& icon_urls,
1999     int icon_types,
2000     const std::vector<int>& desired_sizes,
2001     std::vector<favicon_base::FaviconRawBitmapResult>* bitmap_results) {
2002   // If |page_url| is specified, |icon_types| must be either a single icon
2003   // type or icon types which are equivalent.
2004   DCHECK(!page_url || icon_types == favicon_base::FAVICON ||
2005          icon_types == favicon_base::TOUCH_ICON ||
2006          icon_types == favicon_base::TOUCH_PRECOMPOSED_ICON ||
2007          icon_types ==
2008              (favicon_base::TOUCH_ICON | favicon_base::TOUCH_PRECOMPOSED_ICON));
2009   bitmap_results->clear();
2010
2011   if (!thumbnail_db_) {
2012     return;
2013   }
2014
2015   std::vector<favicon_base::FaviconID> favicon_ids;
2016
2017   // The icon type for which the mappings will the updated and data will be
2018   // returned.
2019   favicon_base::IconType selected_icon_type = favicon_base::INVALID_ICON;
2020
2021   for (size_t i = 0; i < icon_urls.size(); ++i) {
2022     const GURL& icon_url = icon_urls[i];
2023     favicon_base::IconType icon_type_out;
2024     const favicon_base::FaviconID favicon_id =
2025         thumbnail_db_->GetFaviconIDForFaviconURL(
2026             icon_url, icon_types, &icon_type_out);
2027
2028     if (favicon_id) {
2029       // Return and update icon mappings only for the largest icon type. As
2030       // |icon_urls| is not sorted in terms of icon type, clear |favicon_ids|
2031       // if an |icon_url| with a larger icon type is found.
2032       if (icon_type_out > selected_icon_type) {
2033         selected_icon_type = icon_type_out;
2034         favicon_ids.clear();
2035       }
2036       if (icon_type_out == selected_icon_type)
2037         favicon_ids.push_back(favicon_id);
2038     }
2039   }
2040
2041   if (page_url && !favicon_ids.empty()) {
2042     bool mappings_updated =
2043         SetFaviconMappingsForPageAndRedirects(*page_url, selected_icon_type,
2044                                               favicon_ids);
2045     if (mappings_updated) {
2046       SendFaviconChangedNotificationForPageAndRedirects(*page_url);
2047       ScheduleCommit();
2048     }
2049   }
2050
2051   GetFaviconBitmapResultsForBestMatch(favicon_ids, desired_sizes,
2052       bitmap_results);
2053 }
2054
2055 void HistoryBackend::SetFaviconBitmaps(
2056     favicon_base::FaviconID icon_id,
2057     const std::vector<favicon_base::FaviconRawBitmapData>& favicon_bitmap_data,
2058     bool* favicon_bitmaps_changed) {
2059   if (favicon_bitmaps_changed)
2060     *favicon_bitmaps_changed = false;
2061
2062   std::vector<FaviconBitmapIDSize> bitmap_id_sizes;
2063   thumbnail_db_->GetFaviconBitmapIDSizes(icon_id, &bitmap_id_sizes);
2064
2065   std::vector<favicon_base::FaviconRawBitmapData> to_add = favicon_bitmap_data;
2066
2067   for (size_t i = 0; i < bitmap_id_sizes.size(); ++i) {
2068     const gfx::Size& pixel_size = bitmap_id_sizes[i].pixel_size;
2069     std::vector<favicon_base::FaviconRawBitmapData>::iterator match_it =
2070         to_add.end();
2071     for (std::vector<favicon_base::FaviconRawBitmapData>::iterator it =
2072              to_add.begin();
2073          it != to_add.end();
2074          ++it) {
2075       if (it->pixel_size == pixel_size) {
2076         match_it = it;
2077         break;
2078       }
2079     }
2080
2081     FaviconBitmapID bitmap_id = bitmap_id_sizes[i].bitmap_id;
2082     if (match_it == to_add.end()) {
2083       thumbnail_db_->DeleteFaviconBitmap(bitmap_id);
2084
2085       if (favicon_bitmaps_changed)
2086         *favicon_bitmaps_changed = true;
2087     } else {
2088       if (favicon_bitmaps_changed &&
2089           !*favicon_bitmaps_changed &&
2090           IsFaviconBitmapDataEqual(bitmap_id, match_it->bitmap_data)) {
2091         thumbnail_db_->SetFaviconBitmapLastUpdateTime(
2092             bitmap_id, base::Time::Now());
2093       } else {
2094         thumbnail_db_->SetFaviconBitmap(bitmap_id, match_it->bitmap_data,
2095             base::Time::Now());
2096
2097         if (favicon_bitmaps_changed)
2098           *favicon_bitmaps_changed = true;
2099       }
2100       to_add.erase(match_it);
2101     }
2102   }
2103
2104   for (size_t i = 0; i < to_add.size(); ++i) {
2105     thumbnail_db_->AddFaviconBitmap(icon_id, to_add[i].bitmap_data,
2106         base::Time::Now(), to_add[i].pixel_size);
2107
2108     if (favicon_bitmaps_changed)
2109       *favicon_bitmaps_changed = true;
2110   }
2111 }
2112
2113 bool HistoryBackend::ValidateSetFaviconsParams(const std::vector<
2114     favicon_base::FaviconRawBitmapData>& favicon_bitmap_data) const {
2115   typedef std::map<GURL, size_t> BitmapsPerIconURL;
2116   BitmapsPerIconURL num_bitmaps_per_icon_url;
2117   for (size_t i = 0; i < favicon_bitmap_data.size(); ++i) {
2118     if (!favicon_bitmap_data[i].bitmap_data.get())
2119       return false;
2120
2121     const GURL& icon_url = favicon_bitmap_data[i].icon_url;
2122     if (!num_bitmaps_per_icon_url.count(icon_url))
2123       num_bitmaps_per_icon_url[icon_url] = 1u;
2124     else
2125       ++num_bitmaps_per_icon_url[icon_url];
2126   }
2127
2128   if (num_bitmaps_per_icon_url.size() > kMaxFaviconsPerPage)
2129     return false;
2130
2131   for (BitmapsPerIconURL::const_iterator it = num_bitmaps_per_icon_url.begin();
2132        it != num_bitmaps_per_icon_url.end(); ++it) {
2133     if (it->second > kMaxFaviconBitmapsPerIconURL)
2134       return false;
2135   }
2136   return true;
2137 }
2138
2139 bool HistoryBackend::IsFaviconBitmapDataEqual(
2140     FaviconBitmapID bitmap_id,
2141     const scoped_refptr<base::RefCountedMemory>& new_bitmap_data) {
2142   if (!new_bitmap_data.get())
2143     return false;
2144
2145   scoped_refptr<base::RefCountedMemory> original_bitmap_data;
2146   thumbnail_db_->GetFaviconBitmap(bitmap_id,
2147                                   NULL,
2148                                   &original_bitmap_data,
2149                                   NULL);
2150   return new_bitmap_data->Equals(original_bitmap_data);
2151 }
2152
2153 bool HistoryBackend::GetFaviconsFromDB(
2154     const GURL& page_url,
2155     int icon_types,
2156     const std::vector<int>& desired_sizes,
2157     std::vector<favicon_base::FaviconRawBitmapResult>* favicon_bitmap_results) {
2158   DCHECK(favicon_bitmap_results);
2159   favicon_bitmap_results->clear();
2160
2161   if (!db_ || !thumbnail_db_)
2162     return false;
2163
2164   // Time the query.
2165   TimeTicks beginning_time = TimeTicks::Now();
2166
2167   // Get FaviconIDs for |page_url| and one of |icon_types|.
2168   std::vector<IconMapping> icon_mappings;
2169   thumbnail_db_->GetIconMappingsForPageURL(page_url, icon_types,
2170                                            &icon_mappings);
2171   std::vector<favicon_base::FaviconID> favicon_ids;
2172   for (size_t i = 0; i < icon_mappings.size(); ++i)
2173     favicon_ids.push_back(icon_mappings[i].icon_id);
2174
2175   // Populate |favicon_bitmap_results| and |icon_url_sizes|.
2176   bool success = GetFaviconBitmapResultsForBestMatch(favicon_ids,
2177       desired_sizes, favicon_bitmap_results);
2178   UMA_HISTOGRAM_TIMES("History.GetFavIconFromDB",  // historical name
2179                       TimeTicks::Now() - beginning_time);
2180   return success && !favicon_bitmap_results->empty();
2181 }
2182
2183 bool HistoryBackend::GetFaviconBitmapResultsForBestMatch(
2184     const std::vector<favicon_base::FaviconID>& candidate_favicon_ids,
2185     const std::vector<int>& desired_sizes,
2186     std::vector<favicon_base::FaviconRawBitmapResult>* favicon_bitmap_results) {
2187   favicon_bitmap_results->clear();
2188
2189   if (candidate_favicon_ids.empty())
2190     return true;
2191
2192   // Find the FaviconID and the FaviconBitmapIDs which best match
2193   // |desired_size_in_dip| and |desired_scale_factors|.
2194   // TODO(pkotwicz): Select bitmap results from multiple favicons once
2195   // content::FaviconStatus supports multiple icon URLs.
2196   favicon_base::FaviconID best_favicon_id = 0;
2197   std::vector<FaviconBitmapID> best_bitmap_ids;
2198   float highest_score = kSelectFaviconFramesInvalidScore;
2199   for (size_t i = 0; i < candidate_favicon_ids.size(); ++i) {
2200     std::vector<FaviconBitmapIDSize> bitmap_id_sizes;
2201     thumbnail_db_->GetFaviconBitmapIDSizes(candidate_favicon_ids[i],
2202                                            &bitmap_id_sizes);
2203
2204     // Build vector of gfx::Size from |bitmap_id_sizes|.
2205     std::vector<gfx::Size> sizes;
2206     for (size_t j = 0; j < bitmap_id_sizes.size(); ++j)
2207       sizes.push_back(bitmap_id_sizes[j].pixel_size);
2208
2209     std::vector<size_t> candidate_bitmap_indices;
2210     float score = 0;
2211     SelectFaviconFrameIndices(sizes,
2212                               desired_sizes,
2213                               &candidate_bitmap_indices,
2214                               &score);
2215     if (score > highest_score) {
2216       highest_score = score;
2217       best_favicon_id = candidate_favicon_ids[i],
2218       best_bitmap_ids.clear();
2219       for (size_t j = 0; j < candidate_bitmap_indices.size(); ++j) {
2220         size_t candidate_index = candidate_bitmap_indices[j];
2221         best_bitmap_ids.push_back(
2222             bitmap_id_sizes[candidate_index].bitmap_id);
2223       }
2224     }
2225   }
2226
2227   // Construct FaviconRawBitmapResults from |best_favicon_id| and
2228   // |best_bitmap_ids|.
2229   GURL icon_url;
2230   favicon_base::IconType icon_type;
2231   if (!thumbnail_db_->GetFaviconHeader(best_favicon_id, &icon_url,
2232                                        &icon_type)) {
2233     return false;
2234   }
2235
2236   for (size_t i = 0; i < best_bitmap_ids.size(); ++i) {
2237     base::Time last_updated;
2238     favicon_base::FaviconRawBitmapResult bitmap_result;
2239     bitmap_result.icon_url = icon_url;
2240     bitmap_result.icon_type = icon_type;
2241     if (!thumbnail_db_->GetFaviconBitmap(best_bitmap_ids[i],
2242                                          &last_updated,
2243                                          &bitmap_result.bitmap_data,
2244                                          &bitmap_result.pixel_size)) {
2245       return false;
2246     }
2247
2248     bitmap_result.expired = (Time::Now() - last_updated) >
2249         TimeDelta::FromDays(kFaviconRefetchDays);
2250     if (bitmap_result.is_valid())
2251       favicon_bitmap_results->push_back(bitmap_result);
2252   }
2253   return true;
2254 }
2255
2256 bool HistoryBackend::SetFaviconMappingsForPageAndRedirects(
2257     const GURL& page_url,
2258     favicon_base::IconType icon_type,
2259     const std::vector<favicon_base::FaviconID>& icon_ids) {
2260   if (!thumbnail_db_)
2261     return false;
2262
2263   // Find all the pages whose favicons we should set, we want to set it for
2264   // all the pages in the redirect chain if it redirected.
2265   history::RedirectList redirects;
2266   GetCachedRecentRedirects(page_url, &redirects);
2267
2268   bool mappings_changed = false;
2269
2270   // Save page <-> favicon associations.
2271   for (history::RedirectList::const_iterator i(redirects.begin());
2272        i != redirects.end(); ++i) {
2273     mappings_changed |= SetFaviconMappingsForPage(*i, icon_type, icon_ids);
2274   }
2275   return mappings_changed;
2276 }
2277
2278 bool HistoryBackend::SetFaviconMappingsForPage(
2279     const GURL& page_url,
2280     favicon_base::IconType icon_type,
2281     const std::vector<favicon_base::FaviconID>& icon_ids) {
2282   DCHECK_LE(icon_ids.size(), kMaxFaviconsPerPage);
2283   bool mappings_changed = false;
2284
2285   // Two icon types are considered 'equivalent' if one of the icon types is
2286   // TOUCH_ICON and the other is TOUCH_PRECOMPOSED_ICON.
2287   //
2288   // Sets the icon mappings from |page_url| for |icon_type| to the favicons
2289   // with |icon_ids|. Mappings for |page_url| to favicons of type |icon_type|
2290   // whose FaviconID is not in |icon_ids| are removed. All icon mappings for
2291   // |page_url| to favicons of a type equivalent to |icon_type| are removed.
2292   // Remove any favicons which are orphaned as a result of the removal of the
2293   // icon mappings.
2294
2295   std::vector<favicon_base::FaviconID> unmapped_icon_ids = icon_ids;
2296
2297   std::vector<IconMapping> icon_mappings;
2298   thumbnail_db_->GetIconMappingsForPageURL(page_url, &icon_mappings);
2299
2300   for (std::vector<IconMapping>::iterator m = icon_mappings.begin();
2301        m != icon_mappings.end(); ++m) {
2302     std::vector<favicon_base::FaviconID>::iterator icon_id_it = std::find(
2303         unmapped_icon_ids.begin(), unmapped_icon_ids.end(), m->icon_id);
2304
2305     // If the icon mapping already exists, avoid removing it and adding it back.
2306     if (icon_id_it != unmapped_icon_ids.end()) {
2307       unmapped_icon_ids.erase(icon_id_it);
2308       continue;
2309     }
2310
2311     if ((icon_type == favicon_base::TOUCH_ICON &&
2312          m->icon_type == favicon_base::TOUCH_PRECOMPOSED_ICON) ||
2313         (icon_type == favicon_base::TOUCH_PRECOMPOSED_ICON &&
2314          m->icon_type == favicon_base::TOUCH_ICON) ||
2315         (icon_type == m->icon_type)) {
2316       thumbnail_db_->DeleteIconMapping(m->mapping_id);
2317
2318       // Removing the icon mapping may have orphaned the associated favicon so
2319       // we must recheck it. This is not super fast, but this case will get
2320       // triggered rarely, since normally a page will always map to the same
2321       // favicon IDs. It will mostly happen for favicons we import.
2322       if (!thumbnail_db_->HasMappingFor(m->icon_id))
2323         thumbnail_db_->DeleteFavicon(m->icon_id);
2324       mappings_changed = true;
2325     }
2326   }
2327
2328   for (size_t i = 0; i < unmapped_icon_ids.size(); ++i) {
2329     thumbnail_db_->AddIconMapping(page_url, unmapped_icon_ids[i]);
2330     mappings_changed = true;
2331   }
2332   return mappings_changed;
2333 }
2334
2335 void HistoryBackend::GetCachedRecentRedirects(
2336     const GURL& page_url,
2337     history::RedirectList* redirect_list) {
2338   RedirectCache::iterator iter = recent_redirects_.Get(page_url);
2339   if (iter != recent_redirects_.end()) {
2340     *redirect_list = iter->second;
2341
2342     // The redirect chain should have the destination URL as the last item.
2343     DCHECK(!redirect_list->empty());
2344     DCHECK(redirect_list->back() == page_url);
2345   } else {
2346     // No known redirects, construct mock redirect chain containing |page_url|.
2347     redirect_list->push_back(page_url);
2348   }
2349 }
2350
2351 void HistoryBackend::SendFaviconChangedNotificationForPageAndRedirects(
2352     const GURL& page_url) {
2353   history::RedirectList redirect_list;
2354   GetCachedRecentRedirects(page_url, &redirect_list);
2355
2356   scoped_ptr<FaviconChangedDetails> changed_details(new FaviconChangedDetails);
2357   for (size_t i = 0; i < redirect_list.size(); ++i)
2358     changed_details->urls.insert(redirect_list[i]);
2359
2360   BroadcastNotifications(chrome::NOTIFICATION_FAVICON_CHANGED,
2361                          changed_details.PassAs<HistoryDetails>());
2362 }
2363
2364 void HistoryBackend::Commit() {
2365   if (!db_)
2366     return;
2367
2368   // Note that a commit may not actually have been scheduled if a caller
2369   // explicitly calls this instead of using ScheduleCommit. Likewise, we
2370   // may reset the flag written by a pending commit. But this is OK! It
2371   // will merely cause extra commits (which is kind of the idea). We
2372   // could optimize more for this case (we may get two extra commits in
2373   // some cases) but it hasn't been important yet.
2374   CancelScheduledCommit();
2375
2376   db_->CommitTransaction();
2377   DCHECK(db_->transaction_nesting() == 0) << "Somebody left a transaction open";
2378   db_->BeginTransaction();
2379
2380   if (thumbnail_db_) {
2381     thumbnail_db_->CommitTransaction();
2382     DCHECK(thumbnail_db_->transaction_nesting() == 0) <<
2383         "Somebody left a transaction open";
2384     thumbnail_db_->BeginTransaction();
2385   }
2386 }
2387
2388 void HistoryBackend::ScheduleCommit() {
2389   if (scheduled_commit_.get())
2390     return;
2391   scheduled_commit_ = new CommitLaterTask(this);
2392   base::MessageLoop::current()->PostDelayedTask(
2393       FROM_HERE,
2394       base::Bind(&CommitLaterTask::RunCommit, scheduled_commit_.get()),
2395       base::TimeDelta::FromSeconds(kCommitIntervalSeconds));
2396 }
2397
2398 void HistoryBackend::CancelScheduledCommit() {
2399   if (scheduled_commit_.get()) {
2400     scheduled_commit_->Cancel();
2401     scheduled_commit_ = NULL;
2402   }
2403 }
2404
2405 void HistoryBackend::ProcessDBTaskImpl() {
2406   if (!db_) {
2407     // db went away, release all the refs.
2408     ReleaseDBTasks();
2409     return;
2410   }
2411
2412   // Remove any canceled tasks.
2413   while (!db_task_requests_.empty() && db_task_requests_.front()->canceled()) {
2414     db_task_requests_.front()->Release();
2415     db_task_requests_.pop_front();
2416   }
2417   if (db_task_requests_.empty())
2418     return;
2419
2420   // Run the first task.
2421   HistoryDBTaskRequest* request = db_task_requests_.front();
2422   db_task_requests_.pop_front();
2423   if (request->value->RunOnDBThread(this, db_.get())) {
2424     // The task is done. Notify the callback.
2425     request->ForwardResult();
2426     // We AddRef'd the request before adding, need to release it now.
2427     request->Release();
2428   } else {
2429     // Tasks wants to run some more. Schedule it at the end of current tasks.
2430     db_task_requests_.push_back(request);
2431     // And process it after an invoke later.
2432     base::MessageLoop::current()->PostTask(
2433         FROM_HERE, base::Bind(&HistoryBackend::ProcessDBTaskImpl, this));
2434   }
2435 }
2436
2437 void HistoryBackend::ReleaseDBTasks() {
2438   for (std::list<HistoryDBTaskRequest*>::iterator i =
2439        db_task_requests_.begin(); i != db_task_requests_.end(); ++i) {
2440     (*i)->Release();
2441   }
2442   db_task_requests_.clear();
2443 }
2444
2445 ////////////////////////////////////////////////////////////////////////////////
2446 //
2447 // Generic operations
2448 //
2449 ////////////////////////////////////////////////////////////////////////////////
2450
2451 void HistoryBackend::DeleteURLs(const std::vector<GURL>& urls) {
2452   expirer_.DeleteURLs(urls);
2453
2454   db_->GetStartDate(&first_recorded_time_);
2455   // Force a commit, if the user is deleting something for privacy reasons, we
2456   // want to get it on disk ASAP.
2457   Commit();
2458 }
2459
2460 void HistoryBackend::DeleteURL(const GURL& url) {
2461   expirer_.DeleteURL(url);
2462
2463   db_->GetStartDate(&first_recorded_time_);
2464   // Force a commit, if the user is deleting something for privacy reasons, we
2465   // want to get it on disk ASAP.
2466   Commit();
2467 }
2468
2469 void HistoryBackend::ExpireHistoryBetween(
2470     const std::set<GURL>& restrict_urls,
2471     Time begin_time,
2472     Time end_time) {
2473   if (!db_)
2474     return;
2475
2476   if (begin_time.is_null() && (end_time.is_null() || end_time.is_max()) &&
2477       restrict_urls.empty()) {
2478     // Special case deleting all history so it can be faster and to reduce the
2479     // possibility of an information leak.
2480     DeleteAllHistory();
2481   } else {
2482     // Clearing parts of history, have the expirer do the depend
2483     expirer_.ExpireHistoryBetween(restrict_urls, begin_time, end_time);
2484
2485     // Force a commit, if the user is deleting something for privacy reasons,
2486     // we want to get it on disk ASAP.
2487     Commit();
2488   }
2489
2490   if (begin_time <= first_recorded_time_)
2491     db_->GetStartDate(&first_recorded_time_);
2492 }
2493
2494 void HistoryBackend::ExpireHistoryForTimes(
2495     const std::set<base::Time>& times,
2496     base::Time begin_time, base::Time end_time) {
2497   if (times.empty() || !db_)
2498     return;
2499
2500   DCHECK(*times.begin() >= begin_time)
2501       << "Min time is before begin time: "
2502       << times.begin()->ToJsTime() << " v.s. " << begin_time.ToJsTime();
2503   DCHECK(*times.rbegin() < end_time)
2504       << "Max time is after end time: "
2505       << times.rbegin()->ToJsTime() << " v.s. " << end_time.ToJsTime();
2506
2507   history::QueryOptions options;
2508   options.begin_time = begin_time;
2509   options.end_time = end_time;
2510   options.duplicate_policy = QueryOptions::KEEP_ALL_DUPLICATES;
2511   QueryResults results;
2512   QueryHistoryBasic(options, &results);
2513
2514   // 1st pass: find URLs that are visited at one of |times|.
2515   std::set<GURL> urls;
2516   for (size_t i = 0; i < results.size(); ++i) {
2517     if (times.count(results[i].visit_time()) > 0)
2518       urls.insert(results[i].url());
2519   }
2520   if (urls.empty())
2521     return;
2522
2523   // 2nd pass: collect all visit times of those URLs.
2524   std::vector<base::Time> times_to_expire;
2525   for (size_t i = 0; i < results.size(); ++i) {
2526     if (urls.count(results[i].url()))
2527       times_to_expire.push_back(results[i].visit_time());
2528   }
2529
2530   // Put the times in reverse chronological order and remove
2531   // duplicates (for expirer_.ExpireHistoryForTimes()).
2532   std::sort(times_to_expire.begin(), times_to_expire.end(),
2533             std::greater<base::Time>());
2534   times_to_expire.erase(
2535       std::unique(times_to_expire.begin(), times_to_expire.end()),
2536       times_to_expire.end());
2537
2538   // Expires by times and commit.
2539   DCHECK(!times_to_expire.empty());
2540   expirer_.ExpireHistoryForTimes(times_to_expire);
2541   Commit();
2542
2543   DCHECK(times_to_expire.back() >= first_recorded_time_);
2544   // Update |first_recorded_time_| if we expired it.
2545   if (times_to_expire.back() == first_recorded_time_)
2546     db_->GetStartDate(&first_recorded_time_);
2547 }
2548
2549 void HistoryBackend::ExpireHistory(
2550     const std::vector<history::ExpireHistoryArgs>& expire_list) {
2551   if (db_) {
2552     bool update_first_recorded_time = false;
2553
2554     for (std::vector<history::ExpireHistoryArgs>::const_iterator it =
2555          expire_list.begin(); it != expire_list.end(); ++it) {
2556       expirer_.ExpireHistoryBetween(it->urls, it->begin_time, it->end_time);
2557
2558       if (it->begin_time < first_recorded_time_)
2559         update_first_recorded_time = true;
2560     }
2561     Commit();
2562
2563     // Update |first_recorded_time_| if any deletion might have affected it.
2564     if (update_first_recorded_time)
2565       db_->GetStartDate(&first_recorded_time_);
2566   }
2567 }
2568
2569 void HistoryBackend::URLsNoLongerBookmarked(const std::set<GURL>& urls) {
2570   if (!db_)
2571     return;
2572
2573   for (std::set<GURL>::const_iterator i = urls.begin(); i != urls.end(); ++i) {
2574     URLRow url_row;
2575     if (!db_->GetRowForURL(*i, &url_row))
2576       continue;  // The URL isn't in the db; nothing to do.
2577
2578     VisitVector visits;
2579     db_->GetVisitsForURL(url_row.id(), &visits);
2580
2581     if (visits.empty())
2582       expirer_.DeleteURL(*i);  // There are no more visits; nuke the URL.
2583   }
2584 }
2585
2586 void HistoryBackend::DatabaseErrorCallback(int error, sql::Statement* stmt) {
2587   if (!scheduled_kill_db_ && sql::IsErrorCatastrophic(error)) {
2588     scheduled_kill_db_ = true;
2589     // Don't just do the close/delete here, as we are being called by |db| and
2590     // that seems dangerous.
2591     // TODO(shess): Consider changing KillHistoryDatabase() to use
2592     // RazeAndClose().  Then it can be cleared immediately.
2593     base::MessageLoop::current()->PostTask(
2594         FROM_HERE,
2595         base::Bind(&HistoryBackend::KillHistoryDatabase, this));
2596   }
2597 }
2598
2599 void HistoryBackend::KillHistoryDatabase() {
2600   scheduled_kill_db_ = false;
2601   if (!db_)
2602     return;
2603
2604   // Rollback transaction because Raze() cannot be called from within a
2605   // transaction.
2606   db_->RollbackTransaction();
2607   bool success = db_->Raze();
2608   UMA_HISTOGRAM_BOOLEAN("History.KillHistoryDatabaseResult", success);
2609
2610 #if defined(OS_ANDROID)
2611   // Release AndroidProviderBackend before other objects.
2612   android_provider_backend_.reset();
2613 #endif
2614
2615   // The expirer keeps tabs on the active databases. Tell it about the
2616   // databases which will be closed.
2617   expirer_.SetDatabases(NULL, NULL);
2618
2619   // Reopen a new transaction for |db_| for the sake of CloseAllDatabases().
2620   db_->BeginTransaction();
2621   CloseAllDatabases();
2622 }
2623
2624 void HistoryBackend::ProcessDBTask(
2625     scoped_refptr<HistoryDBTaskRequest> request) {
2626   DCHECK(request.get());
2627   if (request->canceled())
2628     return;
2629
2630   bool task_scheduled = !db_task_requests_.empty();
2631   // Make sure we up the refcount of the request. ProcessDBTaskImpl will
2632   // release when done with the task.
2633   request->AddRef();
2634   db_task_requests_.push_back(request.get());
2635   if (!task_scheduled) {
2636     // No other tasks are scheduled. Process request now.
2637     ProcessDBTaskImpl();
2638   }
2639 }
2640
2641 void HistoryBackend::BroadcastNotifications(
2642     int type,
2643     scoped_ptr<HistoryDetails> details) {
2644   // |delegate_| may be NULL if |this| is in the process of closing (closed by
2645   // HistoryService -> HistoryBackend::Closing().
2646   if (delegate_)
2647     delegate_->BroadcastNotifications(type, details.Pass());
2648 }
2649
2650 void HistoryBackend::NotifySyncURLsModified(URLRows* rows) {
2651   if (typed_url_syncable_service_.get())
2652     typed_url_syncable_service_->OnUrlsModified(rows);
2653 }
2654
2655 void HistoryBackend::NotifySyncURLsDeleted(bool all_history,
2656                                            bool expired,
2657                                            URLRows* rows) {
2658   if (typed_url_syncable_service_.get())
2659     typed_url_syncable_service_->OnUrlsDeleted(all_history, expired, rows);
2660 }
2661
2662 // Deleting --------------------------------------------------------------------
2663
2664 void HistoryBackend::DeleteAllHistory() {
2665   // Our approach to deleting all history is:
2666   //  1. Copy the bookmarks and their dependencies to new tables with temporary
2667   //     names.
2668   //  2. Delete the original tables. Since tables can not share pages, we know
2669   //     that any data we don't want to keep is now in an unused page.
2670   //  3. Renaming the temporary tables to match the original.
2671   //  4. Vacuuming the database to delete the unused pages.
2672   //
2673   // Since we are likely to have very few bookmarks and their dependencies
2674   // compared to all history, this is also much faster than just deleting from
2675   // the original tables directly.
2676
2677   // Get the bookmarked URLs.
2678   std::vector<URLAndTitle> starred_urls;
2679   HistoryClient* history_client = GetHistoryClient();
2680   if (history_client)
2681     history_client->GetBookmarks(&starred_urls);
2682
2683   URLRows kept_urls;
2684   for (size_t i = 0; i < starred_urls.size(); i++) {
2685     URLRow row;
2686     if (!db_->GetRowForURL(starred_urls[i].url, &row))
2687       continue;
2688
2689     // Clear the last visit time so when we write these rows they are "clean."
2690     row.set_last_visit(Time());
2691     row.set_visit_count(0);
2692     row.set_typed_count(0);
2693     kept_urls.push_back(row);
2694   }
2695
2696   // Clear thumbnail and favicon history. The favicons for the given URLs will
2697   // be kept.
2698   if (!ClearAllThumbnailHistory(kept_urls)) {
2699     LOG(ERROR) << "Thumbnail history could not be cleared";
2700     // We continue in this error case. If the user wants to delete their
2701     // history, we should delete as much as we can.
2702   }
2703
2704   // ClearAllMainHistory will change the IDs of the URLs in kept_urls.
2705   // Therefore, we clear the list afterwards to make sure nobody uses this
2706   // invalid data.
2707   if (!ClearAllMainHistory(kept_urls))
2708     LOG(ERROR) << "Main history could not be cleared";
2709   kept_urls.clear();
2710
2711   db_->GetStartDate(&first_recorded_time_);
2712
2713   // Send out the notification that history is cleared. The in-memory database
2714   // will pick this up and clear itself.
2715   scoped_ptr<URLsDeletedDetails> details(new URLsDeletedDetails);
2716   details->all_history = true;
2717   NotifySyncURLsDeleted(true, false, NULL);
2718   BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URLS_DELETED,
2719                          details.PassAs<HistoryDetails>());
2720 }
2721
2722 bool HistoryBackend::ClearAllThumbnailHistory(const URLRows& kept_urls) {
2723   if (!thumbnail_db_) {
2724     // When we have no reference to the thumbnail database, maybe there was an
2725     // error opening it. In this case, we just try to blow it away to try to
2726     // fix the error if it exists. This may fail, in which case either the
2727     // file doesn't exist or there's no more we can do.
2728     sql::Connection::Delete(GetFaviconsFileName());
2729
2730     // Older version of the database.
2731     sql::Connection::Delete(GetThumbnailFileName());
2732     return true;
2733   }
2734
2735   // Urls to retain mappings for.
2736   std::vector<GURL> urls_to_keep;
2737   for (URLRows::const_iterator i = kept_urls.begin();
2738        i != kept_urls.end(); ++i) {
2739     urls_to_keep.push_back(i->url());
2740   }
2741
2742   // Isolate from any long-running transaction.
2743   thumbnail_db_->CommitTransaction();
2744   thumbnail_db_->BeginTransaction();
2745
2746   // TODO(shess): If this fails, perhaps the database should be razed
2747   // or deleted.
2748   if (!thumbnail_db_->RetainDataForPageUrls(urls_to_keep)) {
2749     thumbnail_db_->RollbackTransaction();
2750     thumbnail_db_->BeginTransaction();
2751     return false;
2752   }
2753
2754 #if defined(OS_ANDROID)
2755   // TODO (michaelbai): Add the unit test once AndroidProviderBackend is
2756   // avaliable in HistoryBackend.
2757   db_->ClearAndroidURLRows();
2758 #endif
2759
2760   // Vacuum to remove all the pages associated with the dropped tables. There
2761   // must be no transaction open on the table when we do this. We assume that
2762   // our long-running transaction is open, so we complete it and start it again.
2763   DCHECK(thumbnail_db_->transaction_nesting() == 1);
2764   thumbnail_db_->CommitTransaction();
2765   thumbnail_db_->Vacuum();
2766   thumbnail_db_->BeginTransaction();
2767   return true;
2768 }
2769
2770 bool HistoryBackend::ClearAllMainHistory(const URLRows& kept_urls) {
2771   // Create the duplicate URL table. We will copy the kept URLs into this.
2772   if (!db_->CreateTemporaryURLTable())
2773     return false;
2774
2775   // Insert the URLs into the temporary table.
2776   for (URLRows::const_iterator i = kept_urls.begin(); i != kept_urls.end();
2777        ++i) {
2778     db_->AddTemporaryURL(*i);
2779   }
2780
2781   // Replace the original URL table with the temporary one.
2782   if (!db_->CommitTemporaryURLTable())
2783     return false;
2784
2785   // Delete the old tables and recreate them empty.
2786   db_->RecreateAllTablesButURL();
2787
2788   // Vacuum to reclaim the space from the dropped tables. This must be done
2789   // when there is no transaction open, and we assume that our long-running
2790   // transaction is currently open.
2791   db_->CommitTransaction();
2792   db_->Vacuum();
2793   db_->BeginTransaction();
2794   db_->GetStartDate(&first_recorded_time_);
2795
2796   return true;
2797 }
2798
2799 HistoryClient* HistoryBackend::GetHistoryClient() {
2800   if (history_client_)
2801     history_client_->BlockUntilBookmarksLoaded();
2802   return history_client_;
2803 }
2804
2805 void HistoryBackend::NotifyVisitObservers(const VisitRow& visit) {
2806   BriefVisitInfo info;
2807   info.url_id = visit.url_id;
2808   info.time = visit.visit_time;
2809   info.transition = visit.transition;
2810   // If we don't have a delegate yet during setup or shutdown, we will drop
2811   // these notifications.
2812   if (delegate_)
2813     delegate_->NotifyVisitDBObserversOnAddVisit(info);
2814 }
2815
2816 #if defined(OS_ANDROID)
2817 void HistoryBackend::PopulateMostVisitedURLMap() {
2818   MostVisitedURLList most_visited_urls;
2819   QueryMostVisitedURLsImpl(kPageVisitStatsMaxTopSites, kSegmentDataRetention,
2820                            &most_visited_urls);
2821
2822   DCHECK_LE(most_visited_urls.size(), kPageVisitStatsMaxTopSites);
2823   for (size_t i = 0; i < most_visited_urls.size(); ++i) {
2824     most_visited_urls_map_[most_visited_urls[i].url] = i;
2825     for (size_t j = 0; j < most_visited_urls[i].redirects.size(); ++j)
2826       most_visited_urls_map_[most_visited_urls[i].redirects[j]] = i;
2827   }
2828 }
2829
2830 void HistoryBackend::RecordTopPageVisitStats(const GURL& url) {
2831   int rank = kPageVisitStatsMaxTopSites;
2832   std::map<GURL, int>::const_iterator it = most_visited_urls_map_.find(url);
2833   if (it != most_visited_urls_map_.end())
2834     rank = (*it).second;
2835   UMA_HISTOGRAM_ENUMERATION("History.TopSitesVisitsByRank",
2836                             rank, kPageVisitStatsMaxTopSites + 1);
2837 }
2838 #endif
2839
2840 }  // namespace history