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

Side by Side Diff: chrome/browser/predictors/resource_prefetch_predictor_tables.cc

Issue 462423004: Revert CL 117933003. Re-add resource speculative prefetching code. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 3 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2014 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/resource_prefetch_predictor_tables.h"
6
7 #include <algorithm>
8 #include <utility>
Lei Zhang 2014/09/09 03:32:19 nit: blank line after
Zhen Wang 2014/09/13 00:36:32 Done.
9 #include "base/logging.h"
10 #include "base/metrics/histogram.h"
11 #include "base/strings/stringprintf.h"
12 #include "content/public/browser/browser_thread.h"
13 #include "sql/statement.h"
14
15 using content::BrowserThread;
16 using sql::Statement;
17
18 namespace {
19
20 const char kUrlResourceTableName[] = "resource_prefetch_predictor_url";
21 const char kUrlMetadataTableName[] = "resource_prefetch_predictor_url_metadata";
22 const char kHostResourceTableName[] = "resource_prefetch_predictor_host";
23 const char kHostMetadataTableName[] =
24 "resource_prefetch_predictor_host_metadata";
25
26 void BindResourceRowToStatement(
27 const predictors::ResourcePrefetchPredictorTables::ResourceRow& row,
28 const std::string& primary_key,
29 Statement* statement) {
30 statement->BindString(0, primary_key);
31 statement->BindString(1, row.resource_url.spec());
32 statement->BindInt(2, static_cast<int>(row.resource_type));
33 statement->BindInt(3, row.number_of_hits);
34 statement->BindInt(4, row.number_of_misses);
35 statement->BindInt(5, row.consecutive_misses);
36 statement->BindDouble(6, row.average_position);
37 }
38
39 bool StepAndInitializeResourceRow(
40 Statement* statement,
41 predictors::ResourcePrefetchPredictorTables::ResourceRow* row) {
42 if (!statement->Step())
43 return false;
44
45 row->primary_key = statement->ColumnString(0);
46 row->resource_url = GURL(statement->ColumnString(1));
47 row->resource_type = static_cast<content::ResourceType>(
48 statement->ColumnInt(2));
49 row->number_of_hits = statement->ColumnInt(3);
50 row->number_of_misses = statement->ColumnInt(4);
51 row->consecutive_misses = statement->ColumnInt(5);
52 row->average_position = statement->ColumnDouble(6);
53 return true;
54 }
55
56 } // namespace
57
58 namespace predictors {
59
60 // static
61 const size_t ResourcePrefetchPredictorTables::kMaxStringLength = 1024;
62
63 ResourcePrefetchPredictorTables::ResourceRow::ResourceRow()
64 : resource_type(content::RESOURCE_TYPE_LAST_TYPE),
65 number_of_hits(0),
66 number_of_misses(0),
67 consecutive_misses(0),
68 average_position(0.0),
69 score(0.0) {
70 }
71
72 ResourcePrefetchPredictorTables::ResourceRow::ResourceRow(
73 const ResourceRow& other)
74 : primary_key(other.primary_key),
75 resource_url(other.resource_url),
76 resource_type(other.resource_type),
77 number_of_hits(other.number_of_hits),
78 number_of_misses(other.number_of_misses),
79 consecutive_misses(other.consecutive_misses),
80 average_position(other.average_position),
81 score(other.score) {
82 }
83
84 ResourcePrefetchPredictorTables::ResourceRow::ResourceRow(
85 const std::string& i_primary_key,
86 const std::string& i_resource_url,
87 content::ResourceType i_resource_type,
88 int i_number_of_hits,
89 int i_number_of_misses,
90 int i_consecutive_misses,
91 double i_average_position)
92 : primary_key(i_primary_key),
93 resource_url(i_resource_url),
94 resource_type(i_resource_type),
95 number_of_hits(i_number_of_hits),
96 number_of_misses(i_number_of_misses),
97 consecutive_misses(i_consecutive_misses),
98 average_position(i_average_position) {
99 UpdateScore();
100 }
101
102 void ResourcePrefetchPredictorTables::ResourceRow::UpdateScore() {
103 // The score is calculated so that when the rows are sorted, the stylesheets
104 // and scripts appear first, sorted by position(ascending) and then the rest
105 // of the resources sorted by position(ascending).
106 static const int kMaxResourcesPerType = 100;
107 switch (resource_type) {
108 case content::RESOURCE_TYPE_STYLESHEET:
109 case content::RESOURCE_TYPE_SCRIPT:
110 score = (2 * kMaxResourcesPerType) - average_position;
111 break;
112
113 case content::RESOURCE_TYPE_IMAGE:
114 score = kMaxResourcesPerType - average_position;
Lei Zhang 2014/09/09 03:32:20 nit: combine with default? i.e. case content::RES
Zhen Wang 2014/09/13 00:36:32 Done.
115 break;
116
117 default:
118 score = kMaxResourcesPerType - average_position;
119 break;
120 }
121 }
122
123 bool ResourcePrefetchPredictorTables::ResourceRow::operator==(
124 const ResourceRow& rhs) const {
125 return primary_key == rhs.primary_key &&
126 resource_url == rhs.resource_url &&
127 resource_type == rhs.resource_type &&
128 number_of_hits == rhs.number_of_hits &&
129 number_of_misses == rhs.number_of_misses &&
130 consecutive_misses == rhs.consecutive_misses &&
131 average_position == rhs.average_position &&
132 score == rhs.score;
133 }
134
135 bool ResourcePrefetchPredictorTables::ResourceRowSorter::operator()(
136 const ResourceRow& x, const ResourceRow& y) const {
137 return x.score > y.score;
138 }
139
140 ResourcePrefetchPredictorTables::PrefetchData::PrefetchData(
141 PrefetchKeyType i_key_type,
142 const std::string& i_primary_key)
143 : key_type(i_key_type),
144 primary_key(i_primary_key) {
145 }
146
147 ResourcePrefetchPredictorTables::PrefetchData::PrefetchData(
148 const PrefetchData& other)
149 : key_type(other.key_type),
150 primary_key(other.primary_key),
151 last_visit(other.last_visit),
152 resources(other.resources) {
153 }
154
155 ResourcePrefetchPredictorTables::PrefetchData::~PrefetchData() {
156 }
157
158 bool ResourcePrefetchPredictorTables::PrefetchData::operator==(
159 const PrefetchData& rhs) const {
160 return key_type == rhs.key_type && primary_key == rhs.primary_key &&
161 resources == rhs.resources;
162 }
163
164 void ResourcePrefetchPredictorTables::GetAllData(
165 PrefetchDataMap* url_data_map,
166 PrefetchDataMap* host_data_map) {
167 CHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
Lei Zhang 2014/09/09 03:32:19 Generally we DCHECK we are on the correct thread,
Zhen Wang 2014/09/13 00:36:32 Done.
168 if (CantAccessDatabase())
169 return;
170
171 DCHECK(url_data_map);
172 DCHECK(host_data_map);
173 url_data_map->clear();
174 host_data_map->clear();
175
176 std::vector<std::string> urls_to_delete, hosts_to_delete;
177 GetAllDataHelper(PREFETCH_KEY_TYPE_URL, url_data_map, &urls_to_delete);
178 GetAllDataHelper(PREFETCH_KEY_TYPE_HOST, host_data_map, &hosts_to_delete);
179
180 if (!urls_to_delete.empty() || !hosts_to_delete.empty())
181 DeleteData(urls_to_delete, hosts_to_delete);
182 }
183
184 void ResourcePrefetchPredictorTables::UpdateData(
185 const PrefetchData& url_data,
186 const PrefetchData& host_data) {
187 CHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
188 if (CantAccessDatabase())
189 return;
190
191 DCHECK(!url_data.is_host() && host_data.is_host());
192 DCHECK(!url_data.primary_key.empty() || !host_data.primary_key.empty());
193
194 DB()->BeginTransaction();
195
196 bool success = (url_data.primary_key.empty() || UpdateDataHelper(url_data)) &&
197 (host_data.primary_key.empty() || UpdateDataHelper(host_data));
198 if (!success)
199 DB()->RollbackTransaction();
200
201 DB()->CommitTransaction();
202 }
203
204 void ResourcePrefetchPredictorTables::DeleteData(
205 const std::vector<std::string>& urls,
206 const std::vector<std::string>& hosts) {
207 CHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
208 if (CantAccessDatabase())
209 return;
210
211 DCHECK(!urls.empty() || !hosts.empty());
212
213 if (!urls.empty())
214 DeleteDataHelper(PREFETCH_KEY_TYPE_URL, urls);
215 if (!hosts.empty())
216 DeleteDataHelper(PREFETCH_KEY_TYPE_HOST, hosts);
217 }
218
219 void ResourcePrefetchPredictorTables::DeleteSingleDataPoint(
220 const std::string& key,
221 PrefetchKeyType key_type) {
222 CHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
223 if (CantAccessDatabase())
224 return;
225
226 DeleteDataHelper(key_type, std::vector<std::string>(1, key));
227 }
228
229 void ResourcePrefetchPredictorTables::DeleteAllData() {
230 if (CantAccessDatabase())
231 return;
232
233 Statement deleter(DB()->GetUniqueStatement(
234 base::StringPrintf("DELETE FROM %s", kUrlResourceTableName).c_str()));
235 deleter.Run();
236 deleter.Assign(DB()->GetUniqueStatement(
237 base::StringPrintf("DELETE FROM %s", kUrlMetadataTableName).c_str()));
238 deleter.Run();
239 deleter.Assign(DB()->GetUniqueStatement(
240 base::StringPrintf("DELETE FROM %s", kHostResourceTableName).c_str()));
241 deleter.Run();
242 deleter.Assign(DB()->GetUniqueStatement(
243 base::StringPrintf("DELETE FROM %s", kHostMetadataTableName).c_str()));
244 deleter.Run();
245 }
246
247 ResourcePrefetchPredictorTables::ResourcePrefetchPredictorTables()
248 : PredictorTableBase() {
249 }
250
251 ResourcePrefetchPredictorTables::~ResourcePrefetchPredictorTables() {
252 }
253
254 void ResourcePrefetchPredictorTables::GetAllDataHelper(
255 PrefetchKeyType key_type,
256 PrefetchDataMap* data_map,
257 std::vector<std::string>* to_delete) {
258 bool is_host = key_type == PREFETCH_KEY_TYPE_HOST;
259
260 // Read the resources table and organize it per primary key.
261 const char* resource_table_name = is_host ? kHostResourceTableName :
262 kUrlResourceTableName;
263 Statement resource_reader(DB()->GetUniqueStatement(
264 base::StringPrintf("SELECT * FROM %s", resource_table_name).c_str()));
265
266 ResourceRow row;
267 while (StepAndInitializeResourceRow(&resource_reader, &row)) {
268 row.UpdateScore();
269 std::string primary_key = row.primary_key;
270 // Don't need to store primary key since the data is grouped by primary key.
271 row.primary_key.clear();
272
273 PrefetchDataMap::iterator it = data_map->find(primary_key);
274 if (it == data_map->end()) {
275 it = data_map->insert(std::make_pair(
276 primary_key, PrefetchData(key_type, primary_key))).first;
277 }
278 it->second.resources.push_back(row);
279 }
280
281 // Sort each of the resource row vectors by score.
282 for (PrefetchDataMap::iterator it = data_map->begin(); it != data_map->end();
283 ++it) {
284 std::sort(it->second.resources.begin(),
285 it->second.resources.end(),
286 ResourceRowSorter());
287 }
288
289 // Read the metadata and keep track of entries that have metadata, but no
290 // resource entries, so they can be deleted.
291 const char* metadata_table_name = is_host ? kHostMetadataTableName :
292 kUrlMetadataTableName;
293 Statement metadata_reader(DB()->GetUniqueStatement(
294 base::StringPrintf("SELECT * FROM %s", metadata_table_name).c_str()));
295
296 while (metadata_reader.Step()) {
297 std::string primary_key = metadata_reader.ColumnString(0);
298
299 PrefetchDataMap::iterator it = data_map->find(primary_key);
300 if (it != data_map->end()) {
301 int64 last_visit = metadata_reader.ColumnInt64(1);
302 it->second.last_visit = base::Time::FromInternalValue(last_visit);
303 } else {
304 to_delete->push_back(primary_key);
305 }
306 }
307 }
308
309 bool ResourcePrefetchPredictorTables::UpdateDataHelper(
310 const PrefetchData& data) {
311 DCHECK(!data.primary_key.empty());
312
313 if (!StringsAreSmallerThanDBLimit(data)) {
314 UMA_HISTOGRAM_BOOLEAN("ResourcePrefetchPredictor.DbStringTooLong", true);
315 return false;
316 }
317
318 // Delete the older data from both the tables.
319 scoped_ptr<Statement> deleter(data.is_host() ?
320 GetHostResourceDeleteStatement() : GetUrlResourceDeleteStatement());
321 deleter->BindString(0, data.primary_key);
322 if (!deleter->Run())
323 return false;
324
325 deleter.reset(data.is_host() ? GetHostMetadataDeleteStatement() :
326 GetUrlMetadataDeleteStatement());
327 deleter->BindString(0, data.primary_key);
328 if (!deleter->Run())
329 return false;
330
331 // Add the new data to the tables.
332 const ResourceRows& resources = data.resources;
333 for (ResourceRows::const_iterator it = resources.begin();
334 it != resources.end(); ++it) {
335 scoped_ptr<Statement> resource_inserter(data.is_host() ?
336 GetHostResourceUpdateStatement() : GetUrlResourceUpdateStatement());
337 BindResourceRowToStatement(*it, data.primary_key, resource_inserter.get());
338 if (!resource_inserter->Run())
339 return false;
340 }
341
342 scoped_ptr<Statement> metadata_inserter(data.is_host() ?
343 GetHostMetadataUpdateStatement() : GetUrlMetadataUpdateStatement());
344 metadata_inserter->BindString(0, data.primary_key);
345 metadata_inserter->BindInt64(1, data.last_visit.ToInternalValue());
346 if (!metadata_inserter->Run())
347 return false;
348
349 return true;
350 }
351
352 void ResourcePrefetchPredictorTables::DeleteDataHelper(
353 PrefetchKeyType key_type,
354 const std::vector<std::string>& keys) {
355 bool is_host = key_type == PREFETCH_KEY_TYPE_HOST;
356
357 for (std::vector<std::string>::const_iterator it = keys.begin();
358 it != keys.end(); ++it) {
359 scoped_ptr<Statement> deleter(is_host ? GetHostResourceDeleteStatement() :
360 GetUrlResourceDeleteStatement());
361 deleter->BindString(0, *it);
362 deleter->Run();
363
364 deleter.reset(is_host ? GetHostMetadataDeleteStatement() :
365 GetUrlMetadataDeleteStatement());
366 deleter->BindString(0, *it);
367 deleter->Run();
368 }
369 }
370
371 bool ResourcePrefetchPredictorTables::StringsAreSmallerThanDBLimit(
372 const PrefetchData& data) const {
373 if (data.primary_key.length() > kMaxStringLength)
374 return false;
375
376 for (ResourceRows::const_iterator it = data.resources.begin();
377 it != data.resources.end(); ++it) {
378 if (it->resource_url.spec().length() > kMaxStringLength)
379 return false;
380 }
381 return true;
382 }
383
384 void ResourcePrefetchPredictorTables::CreateTableIfNonExistent() {
385 CHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
386 if (CantAccessDatabase())
387 return;
388
389 const char* resource_table_creator =
Lei Zhang 2014/09/09 03:32:20 nit: const char resource_table_creator[]
Zhen Wang 2014/09/13 00:36:32 Done.
390 "CREATE TABLE %s ( "
391 "main_page_url TEXT, "
392 "resource_url TEXT, "
393 "resource_type INTEGER, "
394 "number_of_hits INTEGER, "
395 "number_of_misses INTEGER, "
396 "consecutive_misses INTEGER, "
397 "average_position DOUBLE, "
398 "PRIMARY KEY(main_page_url, resource_url))";
399 const char* metadata_table_creator =
400 "CREATE TABLE %s ( "
401 "main_page_url TEXT, "
402 "last_visit_time INTEGER, "
403 "PRIMARY KEY(main_page_url))";
404
405 sql::Connection* db = DB();
406 bool success =
407 (db->DoesTableExist(kUrlResourceTableName) ||
408 db->Execute(base::StringPrintf(resource_table_creator,
409 kUrlResourceTableName).c_str())) &&
410 (db->DoesTableExist(kUrlMetadataTableName) ||
411 db->Execute(base::StringPrintf(metadata_table_creator,
412 kUrlMetadataTableName).c_str())) &&
413 (db->DoesTableExist(kHostResourceTableName) ||
414 db->Execute(base::StringPrintf(resource_table_creator,
415 kHostResourceTableName).c_str())) &&
416 (db->DoesTableExist(kHostMetadataTableName) ||
417 db->Execute(base::StringPrintf(metadata_table_creator,
418 kHostMetadataTableName).c_str()));
419
420 if (!success)
421 ResetDB();
422 }
423
424 void ResourcePrefetchPredictorTables::LogDatabaseStats() {
425 CHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
426 if (CantAccessDatabase())
427 return;
428
429 Statement statement(DB()->GetUniqueStatement(
430 base::StringPrintf("SELECT count(*) FROM %s",
431 kUrlResourceTableName).c_str()));
432 if (statement.Step())
433 UMA_HISTOGRAM_COUNTS("ResourcePrefetchPredictor.UrlTableRowCount",
434 statement.ColumnInt(0));
435
436 statement.Assign(DB()->GetUniqueStatement(
437 base::StringPrintf("SELECT count(*) FROM %s",
438 kHostResourceTableName).c_str()));
439 if (statement.Step())
440 UMA_HISTOGRAM_COUNTS("ResourcePrefetchPredictor.HostTableRowCount",
441 statement.ColumnInt(0));
442 }
443
444 Statement*
445 ResourcePrefetchPredictorTables::GetUrlResourceDeleteStatement() {
446 return new Statement(DB()->GetCachedStatement(
447 SQL_FROM_HERE,
448 base::StringPrintf("DELETE FROM %s WHERE main_page_url=?",
449 kUrlResourceTableName).c_str()));
450 }
451
452 Statement*
453 ResourcePrefetchPredictorTables::GetUrlResourceUpdateStatement() {
454 return new Statement(DB()->GetCachedStatement(
455 SQL_FROM_HERE,
456 base::StringPrintf(
457 "INSERT INTO %s "
458 "(main_page_url, resource_url, resource_type, number_of_hits, "
459 "number_of_misses, consecutive_misses, average_position) "
460 "VALUES (?,?,?,?,?,?,?)", kUrlResourceTableName).c_str()));
461 }
462
463 Statement*
464 ResourcePrefetchPredictorTables::GetUrlMetadataDeleteStatement() {
465 return new Statement(DB()->GetCachedStatement(
466 SQL_FROM_HERE,
467 base::StringPrintf("DELETE FROM %s WHERE main_page_url=?",
468 kUrlMetadataTableName).c_str()));
469 }
470
471 Statement*
472 ResourcePrefetchPredictorTables::GetUrlMetadataUpdateStatement() {
473 return new Statement(DB()->GetCachedStatement(
474 SQL_FROM_HERE,
475 base::StringPrintf(
476 "INSERT INTO %s (main_page_url, last_visit_time) VALUES (?,?)",
477 kUrlMetadataTableName).c_str()));
478 }
479
480 Statement*
481 ResourcePrefetchPredictorTables::GetHostResourceDeleteStatement() {
482 return new Statement(DB()->GetCachedStatement(
483 SQL_FROM_HERE,
484 base::StringPrintf("DELETE FROM %s WHERE main_page_url=?",
485 kHostResourceTableName).c_str()));
486 }
487
488 Statement*
489 ResourcePrefetchPredictorTables::GetHostResourceUpdateStatement() {
490 return new Statement(DB()->GetCachedStatement(
491 SQL_FROM_HERE,
492 base::StringPrintf(
493 "INSERT INTO %s "
494 "(main_page_url, resource_url, resource_type, number_of_hits, "
495 "number_of_misses, consecutive_misses, average_position) "
496 "VALUES (?,?,?,?,?,?,?)", kHostResourceTableName).c_str()));
497 }
498
499 Statement*
500 ResourcePrefetchPredictorTables::GetHostMetadataDeleteStatement() {
501 return new Statement(DB()->GetCachedStatement(
502 SQL_FROM_HERE,
503 base::StringPrintf("DELETE FROM %s WHERE main_page_url=?",
504 kHostMetadataTableName).c_str()));
505 }
506
507 Statement* ResourcePrefetchPredictorTables::GetHostMetadataUpdateStatement() {
508 return new Statement(DB()->GetCachedStatement(
509 SQL_FROM_HERE,
510 base::StringPrintf(
511 "INSERT INTO %s (main_page_url, last_visit_time) VALUES (?,?)",
512 kHostMetadataTableName).c_str()));
513 }
514
515 } // namespace predictors
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698