Chromium Code Reviews| OLD | NEW |
|---|---|
| (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 | |
| OLD | NEW |