Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(15)

Side by Side Diff: components/previews/core/previews_opt_out_store_sql.cc

Issue 2390773003: Adding a SQL implementation of the backing store for previews opt outs (Closed)
Patch Set: Split black list initialization and construction Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 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 "components/previews/core/previews_opt_out_store_sql.h"
6
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/files/file_util.h"
10 #include "base/location.h"
11 #include "base/memory/ptr_util.h"
12 #include "base/sequenced_task_runner.h"
13 #include "base/threading/thread_task_runner_handle.h"
14 #include "components/previews/core/previews_black_list_item.h"
15 #include "components/previews/core/previews_experiments.h"
16 #include "sql/connection.h"
17 #include "sql/statement.h"
18 #include "sql/transaction.h"
19
20 namespace previews {
21
22 namespace {
23
24 // This is a macro instead of a const, so it can be used inline in other SQL
25 // statements below.
26 #define PREVIEWS_TABLE_NAME "previews_v1"
27
28 // New columns should be added at the end of the list in order to avoid
29 // complicated table upgrade.
30 const char kPreviewsColumns[] =
31 "(host_name VARCHAR NOT NULL DEFAULT '',"
32 " time INTEGER NOT NULL,"
33 " opt_out INTEGER NOT NULL,"
34 " type INTEGER NOT NULL)";
35
36 struct TableInfo {
37 const char* table_name;
38 const char* columns;
39 };
40
41 enum : int {
42 OP_HOST_NAME = 0,
43 OP_TIME,
44 OP_OPT_OUT,
45 OP_TYPE,
46 };
47
48 const TableInfo kPreviewsTable{PREVIEWS_TABLE_NAME, kPreviewsColumns};
49
50 bool CreateTable(sql::Connection* db, const TableInfo& table_info) {
51 std::string sql("CREATE TABLE ");
52 sql += table_info.table_name;
53 sql += table_info.columns;
54 return db->Execute(sql.c_str());
55 }
56
57 void CreateSchema(sql::Connection* db) {
58 sql::Transaction transaction(db);
59 if (!transaction.Begin())
60 return;
61
62 if (!db->DoesTableExist(kPreviewsTable.table_name)) {
63 if (!CreateTable(db, kPreviewsTable))
64 return;
65 }
66
67 transaction.Commit();
68 }
69
70 void InitDatabase(sql::Connection* db, base::FilePath path) {
71 db->set_page_size(4096);
72 db->set_cache_size(250);
73 db->set_histogram_tag("PreviewsOptOut");
74 db->set_exclusive_locking();
75
76 base::File::Error err;
77 if (!base::CreateDirectoryAndGetError(path.DirName(), &err)) {
78 return;
79 }
80 if (!db->Open(path)) {
81 return;
82 }
83 db->Preload();
84
85 CreateSchema(db);
86 }
87
88 void LoadBlackListFromDataBase(
89 sql::Connection* db,
90 scoped_refptr<base::SingleThreadTaskRunner> runner,
91 LoadBlackListCallback callback) {
92 // Gets the table sorted by host and time. Limits the number of hosts using
93 // most recent opt_out time as the limiting function.
94 const char kSql[] =
95 "SELECT full_table.host_name, full_table.time, full_table.opt_out"
96 " FROM " PREVIEWS_TABLE_NAME
97 " full_table INNER JOIN"
98 " (SELECT host_name,"
99 " MAX(CASE WHEN opt_out > 0 THEN time ELSE 0 END) AS max_opt_out_time,"
100 " MAX(time) AS max_time FROM " PREVIEWS_TABLE_NAME
101 " GROUP BY host_name"
102 " ORDER BY max_opt_out_time DESC, max_time DESC"
103 " LIMIT ?) max_host_table"
104 " ON max_host_table.host_name == full_table.host_name"
105 " ORDER BY full_table.host_name, full_table.time DESC";
tbansal1 2016/10/04 15:01:21 Can you comment on why this needs to be ordered by
RyanSturm 2016/10/04 19:10:23 Removed the ORDER BY.
106
107 sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
108 statement.BindInt(0, static_cast<int>(params::MaxInMemoryHostsInBlackList()));
109 std::unique_ptr<BlackListItemMap> black_list_item_map(new BlackListItemMap());
110 // Add the host name, the visit time, and opt out history to
111 // |black_list_item_map|.
112 while (statement.Step()) {
113 std::string host_name = statement.ColumnString(OP_HOST_NAME);
114 BlackListItemMap::iterator iter = black_list_item_map->find(host_name);
115 PreviewsBlackListItem* black_list_item;
116 if (iter == black_list_item_map->end()) {
117 black_list_item = new PreviewsBlackListItem(
118 params::MaxStoredHistoryLengthForBlackList(),
119 params::BlackListOptOutThreshold(), params::BlackListDuration());
120 black_list_item_map->operator[](host_name) =
121 base::WrapUnique(black_list_item);
122 } else {
123 black_list_item = iter->second.get();
124 }
125 // Allows the internal logic of PreviewsBlackListItem to determine how to
126 // evict entries when there are more than
127 // |StoredHistoryLengthForBlackList()| for the host.
128 black_list_item->AddPreviewNavigation(
129 statement.ColumnBool(OP_OPT_OUT),
130 base::Time::FromInternalValue(statement.ColumnInt64(OP_TIME)));
131 }
132
133 runner->PostTask(FROM_HERE,
134 base::Bind(callback, base::Passed(&black_list_item_map)));
135 }
136
137 } // namespace
138
139 PreviewsOptOutStoreSQL::PreviewsOptOutStoreSQL(
140 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
141 scoped_refptr<base::SequencedTaskRunner> background_task_runner,
142 const base::FilePath& path)
143 : io_task_runner_(io_task_runner),
144 background_task_runner_(background_task_runner),
145 db_file_path_(path.AppendASCII("Previews.db")),
146 initialized_(false) {}
147
148 PreviewsOptOutStoreSQL::~PreviewsOptOutStoreSQL() {
149 DCHECK(io_task_runner_->BelongsToCurrentThread());
150 if (db_.get()) {
151 background_task_runner_->DeleteSoon(FROM_HERE, db_.release());
152 }
153 }
154
155 void PreviewsOptOutStoreSQL::AddPreviewNavigation(bool opt_out,
156 const std::string& host_name,
157 PreviewsType type,
158 base::Time now) {}
159
160 void PreviewsOptOutStoreSQL::LoadBlackList(LoadBlackListCallback callback) {
161 DCHECK(io_task_runner_->BelongsToCurrentThread());
162 if (!db_)
163 db_.reset(new sql::Connection());
164 background_task_runner_->PostTask(
165 FROM_HERE, base::Bind(&PreviewsOptOutStoreSQL::LoadBlackListSync,
166 db_.get(), db_file_path_, !initialized_,
167 base::ThreadTaskRunnerHandle::Get(), callback));
168 initialized_ = true;
169 }
170
171 void PreviewsOptOutStoreSQL::LoadBlackListSync(
172 sql::Connection* db,
173 const base::FilePath& path,
174 bool needs_initialization,
175 scoped_refptr<base::SingleThreadTaskRunner> runner,
176 LoadBlackListCallback callback) {
177 if (needs_initialization) {
178 InitDatabase(db, path);
179 }
180
181 if (!db->is_open() || !db->DoesTableExist(kPreviewsTable.table_name)) {
182 std::unique_ptr<BlackListItemMap> black_list_item_map(
183 new BlackListItemMap());
184 runner->PostTask(FROM_HERE,
185 base::Bind(callback, base::Passed(&black_list_item_map)));
186 }
187
188 LoadBlackListFromDataBase(db, runner, callback);
189 }
190
191 } // namespace previews
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698