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/predictors/predictor_database.h"
6
7#include "base/bind.h"
8#include "base/file_util.h"
9#include "base/files/file_path.h"
10#include "base/logging.h"
11#include "base/metrics/histogram.h"
12#include "base/strings/stringprintf.h"
13#include "chrome/browser/predictors/autocomplete_action_predictor_table.h"
14#include "chrome/browser/predictors/logged_in_predictor_table.h"
15#include "chrome/browser/prerender/prerender_field_trial.h"
16#include "chrome/browser/profiles/profile.h"
17#include "content/public/browser/browser_thread.h"
18#include "sql/connection.h"
19#include "sql/statement.h"
20
21using content::BrowserThread;
22
23namespace {
24
25// TODO(shishir): This should move to a more generic name.
26const base::FilePath::CharType kPredictorDatabaseName[] =
27    FILE_PATH_LITERAL("Network Action Predictor");
28
29}  // namespace
30
31namespace predictors {
32
33// Refcounted as it is created, initialized and destroyed on a different thread
34// to the DB thread that is required for all methods performing database access.
35class PredictorDatabaseInternal
36    : public base::RefCountedThreadSafe<PredictorDatabaseInternal> {
37 private:
38  friend class base::RefCountedThreadSafe<PredictorDatabaseInternal>;
39  friend class PredictorDatabase;
40
41  explicit PredictorDatabaseInternal(Profile* profile);
42  virtual ~PredictorDatabaseInternal();
43
44  // Opens the database file from the profile path. Separated from the
45  // constructor to ease construction/destruction of this object on one thread
46  // but database access on the DB thread.
47  void Initialize();
48  void LogDatabaseStats();  //  DB Thread.
49
50  // Cancels pending DB transactions. Should only be called on the UI thread.
51  void SetCancelled();
52
53  base::FilePath db_path_;
54  scoped_ptr<sql::Connection> db_;
55
56  // TODO(shishir): These tables may not need to be refcounted. Maybe move them
57  // to using a WeakPtr instead.
58  scoped_refptr<AutocompleteActionPredictorTable> autocomplete_table_;
59  scoped_refptr<LoggedInPredictorTable> logged_in_table_;
60
61  DISALLOW_COPY_AND_ASSIGN(PredictorDatabaseInternal);
62};
63
64
65PredictorDatabaseInternal::PredictorDatabaseInternal(Profile* profile)
66    : db_path_(profile->GetPath().Append(kPredictorDatabaseName)),
67      db_(new sql::Connection()),
68      autocomplete_table_(new AutocompleteActionPredictorTable()),
69      logged_in_table_(new LoggedInPredictorTable()) {
70  db_->set_histogram_tag("Predictor");
71}
72
73PredictorDatabaseInternal::~PredictorDatabaseInternal() {
74  // The connection pointer needs to be deleted on the DB thread since there
75  // might be a task in progress on the DB thread which uses this connection.
76  if (BrowserThread::IsMessageLoopValid(BrowserThread::DB))
77    BrowserThread::DeleteSoon(BrowserThread::DB, FROM_HERE, db_.release());
78}
79
80void PredictorDatabaseInternal::Initialize() {
81  CHECK(BrowserThread::CurrentlyOn(BrowserThread::DB) ||
82        !BrowserThread::IsMessageLoopValid(BrowserThread::DB));
83  // TODO(tburkard): figure out if we need this.
84  //  db_->set_exclusive_locking();
85  bool success = db_->Open(db_path_);
86
87  if (!success)
88    return;
89
90  autocomplete_table_->Initialize(db_.get());
91  logged_in_table_->Initialize(db_.get());
92
93  LogDatabaseStats();
94}
95
96void PredictorDatabaseInternal::SetCancelled() {
97  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
98        !BrowserThread::IsMessageLoopValid(BrowserThread::UI));
99
100  autocomplete_table_->SetCancelled();
101  logged_in_table_->SetCancelled();
102}
103
104void PredictorDatabaseInternal::LogDatabaseStats() {
105  CHECK(BrowserThread::CurrentlyOn(BrowserThread::DB) ||
106        !BrowserThread::IsMessageLoopValid(BrowserThread::DB));
107
108  int64 db_size;
109  bool success = base::GetFileSize(db_path_, &db_size);
110  DCHECK(success) << "Failed to get file size for " << db_path_.value();
111  UMA_HISTOGRAM_MEMORY_KB("PredictorDatabase.DatabaseSizeKB",
112                          static_cast<int>(db_size / 1024));
113
114  autocomplete_table_->LogDatabaseStats();
115  logged_in_table_->LogDatabaseStats();
116}
117
118PredictorDatabase::PredictorDatabase(Profile* profile)
119    : db_(new PredictorDatabaseInternal(profile)) {
120  BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
121      base::Bind(&PredictorDatabaseInternal::Initialize, db_));
122}
123
124PredictorDatabase::~PredictorDatabase() {
125}
126
127void PredictorDatabase::Shutdown() {
128  db_->SetCancelled();
129}
130
131scoped_refptr<AutocompleteActionPredictorTable>
132    PredictorDatabase::autocomplete_table() {
133  return db_->autocomplete_table_;
134}
135
136scoped_refptr<LoggedInPredictorTable>
137    PredictorDatabase::logged_in_table() {
138  return db_->logged_in_table_;
139}
140
141sql::Connection* PredictorDatabase::GetDatabase() {
142  return db_->db_.get();
143}
144
145}  // namespace predictors
146