| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/file_util.h" | 5 #include "base/file_util.h" |
| 6 #include "base/memory/ref_counted.h" | 6 #include "base/memory/ref_counted.h" |
| 7 #include "base/strings/string_split.h" | 7 #include "base/strings/string_split.h" |
| 8 #include "base/strings/string_util.h" | 8 #include "base/strings/string_util.h" |
| 9 #include "chrome/browser/history/history_types.h" | 9 #include "chrome/browser/history/history_types.h" |
| 10 #include "chrome/browser/history/top_sites.h" | 10 #include "chrome/browser/history/top_sites.h" |
| 11 #include "chrome/browser/history/top_sites_database.h" | 11 #include "chrome/browser/history/top_sites_database.h" |
| 12 #include "chrome/common/thumbnail_score.h" |
| 12 #include "sql/connection.h" | 13 #include "sql/connection.h" |
| 13 #include "sql/transaction.h" | 14 #include "sql/transaction.h" |
| 14 | 15 |
| 16 // Description of database table: |
| 17 // |
| 18 // thumbnails |
| 19 // url URL of the sites for which we have a thumbnail. |
| 20 // url_rank Index of the URL in that thumbnail, 0-based. The thumbnail |
| 21 // with the highest rank will be the next one evicted. Forced |
| 22 // thumbnails have a rank of -1. |
| 23 // title The title to display under that thumbnail. |
| 24 // redirects A space separated list of URLs that are known to redirect |
| 25 // to this url. |
| 26 // boring_score How "boring" that thumbnail is. See ThumbnailScore. |
| 27 // good_clipping True if the thumbnail was clipped from the bottom, keeping |
| 28 // the entire width of the window. See ThumbnailScore. |
| 29 // at_top True if the thumbnail was captured at the top of the |
| 30 // website. |
| 31 // last_updated The time at which this thumbnail was last updated. |
| 32 // load_completed True if the thumbnail was captured after the page load was |
| 33 // completed. |
| 34 // last_forced If this is a forced thumbnail, records the last time it |
| 35 // was forced. If it's not a forced thumbnail, 0. |
| 36 |
| 15 namespace history { | 37 namespace history { |
| 16 | 38 |
| 39 // TODO(beaudoin): Fill revision/date details of Version 3 after landing. |
| 40 // Version 3: by beaudoin@chromium.org |
| 17 // Version 2: eb0b24e6/r87284 by satorux@chromium.org on 2011-05-31 | 41 // Version 2: eb0b24e6/r87284 by satorux@chromium.org on 2011-05-31 |
| 18 // Version 1: 809cc4d8/r64072 by sky@chromium.org on 2010-10-27 | 42 // Version 1: 809cc4d8/r64072 by sky@chromium.org on 2010-10-27 |
| 19 | 43 |
| 20 // From the version 1 to 2, one column was added. Old versions of Chrome | 44 // From the version 1 to 2, one column was added. Old versions of Chrome |
| 21 // should be able to read version 2 files just fine. | 45 // should be able to read version 2 files just fine. Same thing for version 2 |
| 46 // to 3. |
| 22 // NOTE(shess): When changing the version, add a new golden file for | 47 // NOTE(shess): When changing the version, add a new golden file for |
| 23 // the new version and a test to verify that Init() works with it. | 48 // the new version and a test to verify that Init() works with it. |
| 24 static const int kVersionNumber = 2; | 49 static const int kVersionNumber = 3; |
| 25 | 50 |
| 26 TopSitesDatabase::TopSitesDatabase() { | 51 TopSitesDatabase::TopSitesDatabase() { |
| 27 } | 52 } |
| 28 | 53 |
| 29 TopSitesDatabase::~TopSitesDatabase() { | 54 TopSitesDatabase::~TopSitesDatabase() { |
| 30 } | 55 } |
| 31 | 56 |
| 32 bool TopSitesDatabase::Init(const base::FilePath& db_name) { | 57 bool TopSitesDatabase::Init(const base::FilePath& db_name) { |
| 33 bool file_existed = base::PathExists(db_name); | 58 bool file_existed = base::PathExists(db_name); |
| 34 | 59 |
| (...skipping 27 matching lines...) Expand all Loading... |
| 62 if (!InitThumbnailTable()) | 87 if (!InitThumbnailTable()) |
| 63 return false; | 88 return false; |
| 64 | 89 |
| 65 if (meta_table_.GetVersionNumber() == 1) { | 90 if (meta_table_.GetVersionNumber() == 1) { |
| 66 if (!UpgradeToVersion2()) { | 91 if (!UpgradeToVersion2()) { |
| 67 LOG(WARNING) << "Unable to upgrade top sites database to version 2."; | 92 LOG(WARNING) << "Unable to upgrade top sites database to version 2."; |
| 68 return false; | 93 return false; |
| 69 } | 94 } |
| 70 } | 95 } |
| 71 | 96 |
| 97 if (meta_table_.GetVersionNumber() == 2) { |
| 98 if (!UpgradeToVersion3()) { |
| 99 LOG(WARNING) << "Unable to upgrade top sites database to version 3."; |
| 100 return false; |
| 101 } |
| 102 } |
| 103 |
| 72 // Version check. | 104 // Version check. |
| 73 if (meta_table_.GetVersionNumber() != kVersionNumber) | 105 if (meta_table_.GetVersionNumber() != kVersionNumber) |
| 74 return false; | 106 return false; |
| 75 | 107 |
| 76 // Initialization is complete. | 108 // Initialization is complete. |
| 77 if (!transaction.Commit()) | 109 if (!transaction.Commit()) |
| 78 return false; | 110 return false; |
| 79 | 111 |
| 80 return true; | 112 return true; |
| 81 } | 113 } |
| 82 | 114 |
| 83 bool TopSitesDatabase::InitThumbnailTable() { | 115 bool TopSitesDatabase::InitThumbnailTable() { |
| 84 if (!db_->DoesTableExist("thumbnails")) { | 116 if (!db_->DoesTableExist("thumbnails")) { |
| 85 if (!db_->Execute("CREATE TABLE thumbnails (" | 117 if (!db_->Execute("CREATE TABLE thumbnails (" |
| 86 "url LONGVARCHAR PRIMARY KEY," | 118 "url LONGVARCHAR PRIMARY KEY," |
| 87 "url_rank INTEGER ," | 119 "url_rank INTEGER," |
| 88 "title LONGVARCHAR," | 120 "title LONGVARCHAR," |
| 89 "thumbnail BLOB," | 121 "thumbnail BLOB," |
| 90 "redirects LONGVARCHAR," | 122 "redirects LONGVARCHAR," |
| 91 "boring_score DOUBLE DEFAULT 1.0, " | 123 "boring_score DOUBLE DEFAULT 1.0," |
| 92 "good_clipping INTEGER DEFAULT 0, " | 124 "good_clipping INTEGER DEFAULT 0," |
| 93 "at_top INTEGER DEFAULT 0, " | 125 "at_top INTEGER DEFAULT 0," |
| 94 "last_updated INTEGER DEFAULT 0, " | 126 "last_updated INTEGER DEFAULT 0," |
| 95 "load_completed INTEGER DEFAULT 0) ")) { | 127 "load_completed INTEGER DEFAULT 0," |
| 128 "last_forced INTEGER DEFAULT 0)")) { |
| 96 LOG(WARNING) << db_->GetErrorMessage(); | 129 LOG(WARNING) << db_->GetErrorMessage(); |
| 97 return false; | 130 return false; |
| 98 } | 131 } |
| 99 } | 132 } |
| 100 return true; | 133 return true; |
| 101 } | 134 } |
| 102 | 135 |
| 103 bool TopSitesDatabase::UpgradeToVersion2() { | 136 bool TopSitesDatabase::UpgradeToVersion2() { |
| 104 // Add 'load_completed' column. | 137 // Add 'load_completed' column. |
| 105 if (!db_->Execute( | 138 if (!db_->Execute( |
| 106 "ALTER TABLE thumbnails ADD load_completed INTEGER DEFAULT 0")) { | 139 "ALTER TABLE thumbnails ADD load_completed INTEGER DEFAULT 0")) { |
| 107 NOTREACHED(); | 140 NOTREACHED(); |
| 108 return false; | 141 return false; |
| 109 } | 142 } |
| 110 meta_table_.SetVersionNumber(2); | 143 meta_table_.SetVersionNumber(2); |
| 111 return true; | 144 return true; |
| 112 } | 145 } |
| 113 | 146 |
| 147 bool TopSitesDatabase::UpgradeToVersion3() { |
| 148 // Add 'last_forced' column. |
| 149 if (!db_->Execute( |
| 150 "ALTER TABLE thumbnails ADD last_forced INTEGER DEFAULT 0")) { |
| 151 NOTREACHED(); |
| 152 return false; |
| 153 } |
| 154 meta_table_.SetVersionNumber(3); |
| 155 return true; |
| 156 } |
| 157 |
| 114 void TopSitesDatabase::GetPageThumbnails(MostVisitedURLList* urls, | 158 void TopSitesDatabase::GetPageThumbnails(MostVisitedURLList* urls, |
| 115 URLToImagesMap* thumbnails) { | 159 URLToImagesMap* thumbnails) { |
| 116 sql::Statement statement(db_->GetCachedStatement( | 160 sql::Statement statement(db_->GetCachedStatement( |
| 117 SQL_FROM_HERE, | 161 SQL_FROM_HERE, |
| 118 "SELECT url, url_rank, title, thumbnail, redirects, " | 162 "SELECT url, url_rank, title, thumbnail, redirects, " |
| 119 "boring_score, good_clipping, at_top, last_updated, load_completed " | 163 "boring_score, good_clipping, at_top, last_updated, load_completed, " |
| 120 "FROM thumbnails ORDER BY url_rank ")); | 164 "last_forced FROM thumbnails ORDER BY url_rank, last_forced")); |
| 121 | 165 |
| 122 if (!statement.is_valid()) { | 166 if (!statement.is_valid()) { |
| 123 LOG(WARNING) << db_->GetErrorMessage(); | 167 LOG(WARNING) << db_->GetErrorMessage(); |
| 124 return; | 168 return; |
| 125 } | 169 } |
| 126 | 170 |
| 127 urls->clear(); | 171 urls->clear(); |
| 128 thumbnails->clear(); | 172 thumbnails->clear(); |
| 129 | 173 |
| 130 while (statement.Step()) { | 174 while (statement.Step()) { |
| 131 // Results are sorted by url_rank. | 175 // Results are sorted by url_rank. For forced thumbnails with url_rank = -1, |
| 176 // thumbnails are sorted by last_forced. |
| 132 MostVisitedURL url; | 177 MostVisitedURL url; |
| 133 GURL gurl(statement.ColumnString(0)); | 178 GURL gurl(statement.ColumnString(0)); |
| 134 url.url = gurl; | 179 url.url = gurl; |
| 135 url.title = statement.ColumnString16(2); | 180 url.title = statement.ColumnString16(2); |
| 181 url.last_forced_time = |
| 182 base::Time::FromInternalValue(statement.ColumnInt64(10)); |
| 136 std::string redirects = statement.ColumnString(4); | 183 std::string redirects = statement.ColumnString(4); |
| 137 SetRedirects(redirects, &url); | 184 SetRedirects(redirects, &url); |
| 138 urls->push_back(url); | 185 urls->push_back(url); |
| 139 | 186 |
| 140 std::vector<unsigned char> data; | 187 std::vector<unsigned char> data; |
| 141 statement.ColumnBlobAsVector(3, &data); | 188 statement.ColumnBlobAsVector(3, &data); |
| 142 Images thumbnail; | 189 Images thumbnail; |
| 143 if (!data.empty()) | 190 if (!data.empty()) |
| 144 thumbnail.thumbnail = base::RefCountedBytes::TakeVector(&data); | 191 thumbnail.thumbnail = base::RefCountedBytes::TakeVector(&data); |
| 145 thumbnail.thumbnail_score.boring_score = statement.ColumnDouble(5); | 192 thumbnail.thumbnail_score.boring_score = statement.ColumnDouble(5); |
| 146 thumbnail.thumbnail_score.good_clipping = statement.ColumnBool(6); | 193 thumbnail.thumbnail_score.good_clipping = statement.ColumnBool(6); |
| 147 thumbnail.thumbnail_score.at_top = statement.ColumnBool(7); | 194 thumbnail.thumbnail_score.at_top = statement.ColumnBool(7); |
| 148 thumbnail.thumbnail_score.time_at_snapshot = | 195 thumbnail.thumbnail_score.time_at_snapshot = |
| 149 base::Time::FromInternalValue(statement.ColumnInt64(8)); | 196 base::Time::FromInternalValue(statement.ColumnInt64(8)); |
| 150 thumbnail.thumbnail_score.load_completed = statement.ColumnBool(9); | 197 thumbnail.thumbnail_score.load_completed = statement.ColumnBool(9); |
| 151 | |
| 152 (*thumbnails)[gurl] = thumbnail; | 198 (*thumbnails)[gurl] = thumbnail; |
| 153 } | 199 } |
| 154 } | 200 } |
| 155 | 201 |
| 156 // static | 202 // static |
| 157 std::string TopSitesDatabase::GetRedirects(const MostVisitedURL& url) { | 203 std::string TopSitesDatabase::GetRedirects(const MostVisitedURL& url) { |
| 158 std::vector<std::string> redirects; | 204 std::vector<std::string> redirects; |
| 159 for (size_t i = 0; i < url.redirects.size(); i++) | 205 for (size_t i = 0; i < url.redirects.size(); i++) |
| 160 redirects.push_back(url.redirects[i].spec()); | 206 redirects.push_back(url.redirects[i].spec()); |
| 161 return JoinString(redirects, ' '); | 207 return JoinString(redirects, ' '); |
| 162 } | 208 } |
| 163 | 209 |
| 164 // static | 210 // static |
| 165 void TopSitesDatabase::SetRedirects(const std::string& redirects, | 211 void TopSitesDatabase::SetRedirects(const std::string& redirects, |
| 166 MostVisitedURL* url) { | 212 MostVisitedURL* url) { |
| 167 std::vector<std::string> redirects_vector; | 213 std::vector<std::string> redirects_vector; |
| 168 base::SplitStringAlongWhitespace(redirects, &redirects_vector); | 214 base::SplitStringAlongWhitespace(redirects, &redirects_vector); |
| 169 for (size_t i = 0; i < redirects_vector.size(); ++i) | 215 for (size_t i = 0; i < redirects_vector.size(); ++i) |
| 170 url->redirects.push_back(GURL(redirects_vector[i])); | 216 url->redirects.push_back(GURL(redirects_vector[i])); |
| 171 } | 217 } |
| 172 | 218 |
| 173 void TopSitesDatabase::SetPageThumbnail(const MostVisitedURL& url, | 219 void TopSitesDatabase::SetPageThumbnail(const MostVisitedURL& url, |
| 174 int new_rank, | 220 int new_rank, |
| 175 const Images& thumbnail) { | 221 const Images& thumbnail) { |
| 176 sql::Transaction transaction(db_.get()); | 222 sql::Transaction transaction(db_.get()); |
| 177 transaction.Begin(); | 223 transaction.Begin(); |
| 178 | 224 |
| 179 int rank = GetURLRank(url); | 225 int rank = GetURLRank(url); |
| 180 if (rank == -1) { | 226 if (rank == kRankOfNonExistingURL) { |
| 181 AddPageThumbnail(url, new_rank, thumbnail); | 227 AddPageThumbnail(url, new_rank, thumbnail); |
| 182 } else { | 228 } else { |
| 183 UpdatePageRankNoTransaction(url, new_rank); | 229 UpdatePageRankNoTransaction(url, new_rank); |
| 184 UpdatePageThumbnail(url, thumbnail); | 230 UpdatePageThumbnail(url, thumbnail); |
| 185 } | 231 } |
| 186 | 232 |
| 187 transaction.Commit(); | 233 transaction.Commit(); |
| 188 } | 234 } |
| 189 | 235 |
| 190 bool TopSitesDatabase::UpdatePageThumbnail( | 236 bool TopSitesDatabase::UpdatePageThumbnail( |
| 191 const MostVisitedURL& url, const Images& thumbnail) { | 237 const MostVisitedURL& url, const Images& thumbnail) { |
| 192 sql::Statement statement(db_->GetCachedStatement( | 238 sql::Statement statement(db_->GetCachedStatement( |
| 193 SQL_FROM_HERE, | 239 SQL_FROM_HERE, |
| 194 "UPDATE thumbnails SET " | 240 "UPDATE thumbnails SET " |
| 195 "title = ?, thumbnail = ?, redirects = ?, " | 241 "title = ?, thumbnail = ?, redirects = ?, " |
| 196 "boring_score = ?, good_clipping = ?, at_top = ?, last_updated = ?, " | 242 "boring_score = ?, good_clipping = ?, at_top = ?, last_updated = ?, " |
| 197 "load_completed = ? " | 243 "load_completed = ?, last_forced = ?" |
| 198 "WHERE url = ? ")); | 244 "WHERE url = ? ")); |
| 199 statement.BindString16(0, url.title); | 245 statement.BindString16(0, url.title); |
| 200 if (thumbnail.thumbnail.get() && thumbnail.thumbnail->front()) { | 246 if (thumbnail.thumbnail.get() && thumbnail.thumbnail->front()) { |
| 201 statement.BindBlob(1, thumbnail.thumbnail->front(), | 247 statement.BindBlob(1, thumbnail.thumbnail->front(), |
| 202 static_cast<int>(thumbnail.thumbnail->size())); | 248 static_cast<int>(thumbnail.thumbnail->size())); |
| 203 } | 249 } |
| 204 statement.BindString(2, GetRedirects(url)); | 250 statement.BindString(2, GetRedirects(url)); |
| 205 const ThumbnailScore& score = thumbnail.thumbnail_score; | 251 const ThumbnailScore& score = thumbnail.thumbnail_score; |
| 206 statement.BindDouble(3, score.boring_score); | 252 statement.BindDouble(3, score.boring_score); |
| 207 statement.BindBool(4, score.good_clipping); | 253 statement.BindBool(4, score.good_clipping); |
| 208 statement.BindBool(5, score.at_top); | 254 statement.BindBool(5, score.at_top); |
| 209 statement.BindInt64(6, score.time_at_snapshot.ToInternalValue()); | 255 statement.BindInt64(6, score.time_at_snapshot.ToInternalValue()); |
| 210 statement.BindBool(7, score.load_completed); | 256 statement.BindBool(7, score.load_completed); |
| 211 statement.BindString(8, url.url.spec()); | 257 statement.BindInt64(8, url.last_forced_time.ToInternalValue()); |
| 258 statement.BindString(9, url.url.spec()); |
| 212 | 259 |
| 213 return statement.Run(); | 260 return statement.Run(); |
| 214 } | 261 } |
| 215 | 262 |
| 216 void TopSitesDatabase::AddPageThumbnail(const MostVisitedURL& url, | 263 void TopSitesDatabase::AddPageThumbnail(const MostVisitedURL& url, |
| 217 int new_rank, | 264 int new_rank, |
| 218 const Images& thumbnail) { | 265 const Images& thumbnail) { |
| 219 int count = GetRowCount(); | |
| 220 | |
| 221 sql::Statement statement(db_->GetCachedStatement( | 266 sql::Statement statement(db_->GetCachedStatement( |
| 222 SQL_FROM_HERE, | 267 SQL_FROM_HERE, |
| 223 "INSERT OR REPLACE INTO thumbnails " | 268 "INSERT OR REPLACE INTO thumbnails " |
| 224 "(url, url_rank, title, thumbnail, redirects, " | 269 "(url, url_rank, title, thumbnail, redirects, " |
| 225 "boring_score, good_clipping, at_top, last_updated, load_completed) " | 270 "boring_score, good_clipping, at_top, last_updated, load_completed, " |
| 226 "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")); | 271 "last_forced) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")); |
| 227 statement.BindString(0, url.url.spec()); | 272 statement.BindString(0, url.url.spec()); |
| 228 statement.BindInt(1, count); // Make it the last url. | 273 statement.BindInt(1, kRankOfForcedURL); // Fist make it a forced thumbnail. |
| 229 statement.BindString16(2, url.title); | 274 statement.BindString16(2, url.title); |
| 230 if (thumbnail.thumbnail.get() && thumbnail.thumbnail->front()) { | 275 if (thumbnail.thumbnail.get() && thumbnail.thumbnail->front()) { |
| 231 statement.BindBlob(3, thumbnail.thumbnail->front(), | 276 statement.BindBlob(3, thumbnail.thumbnail->front(), |
| 232 static_cast<int>(thumbnail.thumbnail->size())); | 277 static_cast<int>(thumbnail.thumbnail->size())); |
| 233 } | 278 } |
| 234 statement.BindString(4, GetRedirects(url)); | 279 statement.BindString(4, GetRedirects(url)); |
| 235 const ThumbnailScore& score = thumbnail.thumbnail_score; | 280 const ThumbnailScore& score = thumbnail.thumbnail_score; |
| 236 statement.BindDouble(5, score.boring_score); | 281 statement.BindDouble(5, score.boring_score); |
| 237 statement.BindBool(6, score.good_clipping); | 282 statement.BindBool(6, score.good_clipping); |
| 238 statement.BindBool(7, score.at_top); | 283 statement.BindBool(7, score.at_top); |
| 239 statement.BindInt64(8, score.time_at_snapshot.ToInternalValue()); | 284 statement.BindInt64(8, score.time_at_snapshot.ToInternalValue()); |
| 240 statement.BindBool(9, score.load_completed); | 285 statement.BindBool(9, score.load_completed); |
| 286 int64 last_forced = url.last_forced_time.ToInternalValue(); |
| 287 DCHECK((last_forced == 0) == (new_rank != kRankOfForcedURL)) |
| 288 << "Thumbnail without a forced time stamp has a forced rank, or the " |
| 289 << "opposite."; |
| 290 statement.BindInt64(10, last_forced); |
| 241 if (!statement.Run()) | 291 if (!statement.Run()) |
| 242 return; | 292 return; |
| 243 | 293 |
| 244 UpdatePageRankNoTransaction(url, new_rank); | 294 // Update rank if this is not a forced thumbnail. |
| 295 if (new_rank != kRankOfForcedURL) |
| 296 UpdatePageRankNoTransaction(url, new_rank); |
| 245 } | 297 } |
| 246 | 298 |
| 247 void TopSitesDatabase::UpdatePageRank(const MostVisitedURL& url, | 299 void TopSitesDatabase::UpdatePageRank(const MostVisitedURL& url, |
| 248 int new_rank) { | 300 int new_rank) { |
| 301 DCHECK((url.last_forced_time.ToInternalValue() == 0) == |
| 302 (new_rank != kRankOfForcedURL)) |
| 303 << "Thumbnail without a forced time stamp has a forced rank, or the " |
| 304 << "opposite."; |
| 249 sql::Transaction transaction(db_.get()); | 305 sql::Transaction transaction(db_.get()); |
| 250 transaction.Begin(); | 306 transaction.Begin(); |
| 251 UpdatePageRankNoTransaction(url, new_rank); | 307 UpdatePageRankNoTransaction(url, new_rank); |
| 252 transaction.Commit(); | 308 transaction.Commit(); |
| 253 } | 309 } |
| 254 | 310 |
| 255 // Caller should have a transaction open. | 311 // Caller should have a transaction open. |
| 256 void TopSitesDatabase::UpdatePageRankNoTransaction( | 312 void TopSitesDatabase::UpdatePageRankNoTransaction( |
| 257 const MostVisitedURL& url, int new_rank) { | 313 const MostVisitedURL& url, int new_rank) { |
| 258 DCHECK_GT(db_->transaction_nesting(), 0); | 314 DCHECK_GT(db_->transaction_nesting(), 0); |
| 315 |
| 259 int prev_rank = GetURLRank(url); | 316 int prev_rank = GetURLRank(url); |
| 260 if (prev_rank == -1) { | 317 if (prev_rank == kRankOfNonExistingURL) { |
| 261 LOG(WARNING) << "Updating rank of an unknown URL: " << url.url.spec(); | 318 LOG(WARNING) << "Updating rank of an unknown URL: " << url.url.spec(); |
| 262 return; | 319 return; |
| 263 } | 320 } |
| 264 | 321 |
| 265 // Shift the ranks. | 322 // Shift the ranks. |
| 266 if (prev_rank > new_rank) { | 323 if (prev_rank > new_rank) { |
| 267 // Shift up | 324 if (new_rank == kRankOfForcedURL) { |
| 268 sql::Statement shift_statement(db_->GetCachedStatement( | 325 // From non-forced to forced, shift down. |
| 269 SQL_FROM_HERE, | 326 // Example: 2 -> -1 |
| 270 "UPDATE thumbnails " | 327 // -1, -1, -1, 0, 1, [2 -> -1], [3 -> 2], [4 -> 3] |
| 271 "SET url_rank = url_rank + 1 " | 328 sql::Statement shift_statement(db_->GetCachedStatement( |
| 272 "WHERE url_rank >= ? AND url_rank < ?")); | 329 SQL_FROM_HERE, |
| 273 shift_statement.BindInt(0, new_rank); | 330 "UPDATE thumbnails " |
| 274 shift_statement.BindInt(1, prev_rank); | 331 "SET url_rank = url_rank - 1 " |
| 275 shift_statement.Run(); | 332 "WHERE url_rank > ?")); |
| 333 shift_statement.BindInt(0, prev_rank); |
| 334 shift_statement.Run(); |
| 335 } else { |
| 336 // From non-forced to non-forced, shift up. |
| 337 // Example: 3 -> 1 |
| 338 // -1, -1, -1, 0, [1 -> 2], [2 -> 3], [3 -> 1], 4 |
| 339 sql::Statement shift_statement(db_->GetCachedStatement( |
| 340 SQL_FROM_HERE, |
| 341 "UPDATE thumbnails " |
| 342 "SET url_rank = url_rank + 1 " |
| 343 "WHERE url_rank >= ? AND url_rank < ?")); |
| 344 shift_statement.BindInt(0, new_rank); |
| 345 shift_statement.BindInt(1, prev_rank); |
| 346 shift_statement.Run(); |
| 347 } |
| 276 } else if (prev_rank < new_rank) { | 348 } else if (prev_rank < new_rank) { |
| 277 // Shift down | 349 if (prev_rank == kRankOfForcedURL) { |
| 278 sql::Statement shift_statement(db_->GetCachedStatement( | 350 // From non-forced to forced, shift up. |
| 279 SQL_FROM_HERE, | 351 // Example: -1 -> 2 |
| 280 "UPDATE thumbnails " | 352 // -1, [-1 -> 2], -1, 0, 1, [2 -> 3], [3 -> 4], [4 -> 5] |
| 281 "SET url_rank = url_rank - 1 " | 353 sql::Statement shift_statement(db_->GetCachedStatement( |
| 282 "WHERE url_rank > ? AND url_rank <= ?")); | 354 SQL_FROM_HERE, |
| 283 shift_statement.BindInt(0, prev_rank); | 355 "UPDATE thumbnails " |
| 284 shift_statement.BindInt(1, new_rank); | 356 "SET url_rank = url_rank + 1 " |
| 285 shift_statement.Run(); | 357 "WHERE url_rank >= ?")); |
| 358 shift_statement.BindInt(0, new_rank); |
| 359 shift_statement.Run(); |
| 360 } else { |
| 361 // From non-forced to non-forced, shift down. |
| 362 // Example: 1 -> 3. |
| 363 // -1, -1, -1, 0, [1 -> 3], [2 -> 1], [3 -> 2], 4 |
| 364 sql::Statement shift_statement(db_->GetCachedStatement( |
| 365 SQL_FROM_HERE, |
| 366 "UPDATE thumbnails " |
| 367 "SET url_rank = url_rank - 1 " |
| 368 "WHERE url_rank > ? AND url_rank <= ?")); |
| 369 shift_statement.BindInt(0, prev_rank); |
| 370 shift_statement.BindInt(1, new_rank); |
| 371 shift_statement.Run(); |
| 372 } |
| 286 } | 373 } |
| 287 | 374 |
| 288 // Set the url's rank. | 375 // Set the url's rank and last_forced, since the latter changes when a URL |
| 376 // goes from forced to non-forced and vice-versa. |
| 289 sql::Statement set_statement(db_->GetCachedStatement( | 377 sql::Statement set_statement(db_->GetCachedStatement( |
| 290 SQL_FROM_HERE, | 378 SQL_FROM_HERE, |
| 291 "UPDATE thumbnails " | 379 "UPDATE thumbnails " |
| 292 "SET url_rank = ? " | 380 "SET url_rank = ?, last_forced = ? " |
| 293 "WHERE url == ?")); | 381 "WHERE url == ?")); |
| 294 set_statement.BindInt(0, new_rank); | 382 set_statement.BindInt(0, new_rank); |
| 295 set_statement.BindString(1, url.url.spec()); | 383 set_statement.BindInt64(1, url.last_forced_time.ToInternalValue()); |
| 384 set_statement.BindString(2, url.url.spec()); |
| 296 set_statement.Run(); | 385 set_statement.Run(); |
| 297 } | 386 } |
| 298 | 387 |
| 299 bool TopSitesDatabase::GetPageThumbnail(const GURL& url, | 388 bool TopSitesDatabase::GetPageThumbnail(const GURL& url, |
| 300 Images* thumbnail) { | 389 Images* thumbnail) { |
| 301 sql::Statement statement(db_->GetCachedStatement( | 390 sql::Statement statement(db_->GetCachedStatement( |
| 302 SQL_FROM_HERE, | 391 SQL_FROM_HERE, |
| 303 "SELECT thumbnail, boring_score, good_clipping, at_top, last_updated " | 392 "SELECT thumbnail, boring_score, good_clipping, at_top, last_updated " |
| 304 "FROM thumbnails WHERE url=?")); | 393 "FROM thumbnails WHERE url=?")); |
| 305 statement.BindString(0, url.spec()); | 394 statement.BindString(0, url.spec()); |
| 306 if (!statement.Step()) | 395 if (!statement.Step()) |
| 307 return false; | 396 return false; |
| 308 | 397 |
| 309 std::vector<unsigned char> data; | 398 std::vector<unsigned char> data; |
| 310 statement.ColumnBlobAsVector(0, &data); | 399 statement.ColumnBlobAsVector(0, &data); |
| 311 thumbnail->thumbnail = base::RefCountedBytes::TakeVector(&data); | 400 thumbnail->thumbnail = base::RefCountedBytes::TakeVector(&data); |
| 312 thumbnail->thumbnail_score.boring_score = statement.ColumnDouble(1); | 401 thumbnail->thumbnail_score.boring_score = statement.ColumnDouble(1); |
| 313 thumbnail->thumbnail_score.good_clipping = statement.ColumnBool(2); | 402 thumbnail->thumbnail_score.good_clipping = statement.ColumnBool(2); |
| 314 thumbnail->thumbnail_score.at_top = statement.ColumnBool(3); | 403 thumbnail->thumbnail_score.at_top = statement.ColumnBool(3); |
| 315 thumbnail->thumbnail_score.time_at_snapshot = | 404 thumbnail->thumbnail_score.time_at_snapshot = |
| 316 base::Time::FromInternalValue(statement.ColumnInt64(4)); | 405 base::Time::FromInternalValue(statement.ColumnInt64(4)); |
| 317 return true; | 406 return true; |
| 318 } | 407 } |
| 319 | 408 |
| 320 int TopSitesDatabase::GetRowCount() { | |
| 321 sql::Statement select_statement(db_->GetCachedStatement( | |
| 322 SQL_FROM_HERE, | |
| 323 "SELECT COUNT (url) FROM thumbnails")); | |
| 324 if (select_statement.Step()) | |
| 325 return select_statement.ColumnInt(0); | |
| 326 | |
| 327 return 0; | |
| 328 } | |
| 329 | |
| 330 int TopSitesDatabase::GetURLRank(const MostVisitedURL& url) { | 409 int TopSitesDatabase::GetURLRank(const MostVisitedURL& url) { |
| 331 sql::Statement select_statement(db_->GetCachedStatement( | 410 sql::Statement select_statement(db_->GetCachedStatement( |
| 332 SQL_FROM_HERE, | 411 SQL_FROM_HERE, |
| 333 "SELECT url_rank " | 412 "SELECT url_rank " |
| 334 "FROM thumbnails WHERE url=?")); | 413 "FROM thumbnails WHERE url=?")); |
| 335 select_statement.BindString(0, url.url.spec()); | 414 select_statement.BindString(0, url.url.spec()); |
| 336 if (select_statement.Step()) | 415 if (select_statement.Step()) |
| 337 return select_statement.ColumnInt(0); | 416 return select_statement.ColumnInt(0); |
| 338 | 417 |
| 339 return -1; | 418 return kRankOfNonExistingURL; |
| 340 } | 419 } |
| 341 | 420 |
| 342 // Remove the record for this URL. Returns true iff removed successfully. | 421 // Remove the record for this URL. Returns true iff removed successfully. |
| 343 bool TopSitesDatabase::RemoveURL(const MostVisitedURL& url) { | 422 bool TopSitesDatabase::RemoveURL(const MostVisitedURL& url) { |
| 344 int old_rank = GetURLRank(url); | 423 int old_rank = GetURLRank(url); |
| 345 if (old_rank < 0) | 424 if (old_rank == kRankOfNonExistingURL) |
| 346 return false; | 425 return false; |
| 347 | 426 |
| 348 sql::Transaction transaction(db_.get()); | 427 sql::Transaction transaction(db_.get()); |
| 349 transaction.Begin(); | 428 transaction.Begin(); |
| 350 // Decrement all following ranks. | 429 if (old_rank != kRankOfForcedURL) { |
| 351 sql::Statement shift_statement(db_->GetCachedStatement( | 430 // Decrement all following ranks. |
| 352 SQL_FROM_HERE, | 431 sql::Statement shift_statement(db_->GetCachedStatement( |
| 353 "UPDATE thumbnails " | 432 SQL_FROM_HERE, |
| 354 "SET url_rank = url_rank - 1 " | 433 "UPDATE thumbnails " |
| 355 "WHERE url_rank > ?")); | 434 "SET url_rank = url_rank - 1 " |
| 356 shift_statement.BindInt(0, old_rank); | 435 "WHERE url_rank > ?")); |
| 436 shift_statement.BindInt(0, old_rank); |
| 357 | 437 |
| 358 if (!shift_statement.Run()) | 438 if (!shift_statement.Run()) |
| 359 return false; | 439 return false; |
| 440 } |
| 360 | 441 |
| 361 sql::Statement delete_statement( | 442 sql::Statement delete_statement( |
| 362 db_->GetCachedStatement(SQL_FROM_HERE, | 443 db_->GetCachedStatement(SQL_FROM_HERE, |
| 363 "DELETE FROM thumbnails WHERE url = ?")); | 444 "DELETE FROM thumbnails WHERE url = ?")); |
| 364 delete_statement.BindString(0, url.url.spec()); | 445 delete_statement.BindString(0, url.url.spec()); |
| 365 | 446 |
| 366 if (!delete_statement.Run()) | 447 if (!delete_statement.Run()) |
| 367 return false; | 448 return false; |
| 368 | 449 |
| 369 return transaction.Commit(); | 450 return transaction.Commit(); |
| 370 } | 451 } |
| 371 | 452 |
| 372 sql::Connection* TopSitesDatabase::CreateDB(const base::FilePath& db_name) { | 453 sql::Connection* TopSitesDatabase::CreateDB(const base::FilePath& db_name) { |
| 373 scoped_ptr<sql::Connection> db(new sql::Connection()); | 454 scoped_ptr<sql::Connection> db(new sql::Connection()); |
| 374 // Settings copied from ThumbnailDatabase. | 455 // Settings copied from ThumbnailDatabase. |
| 375 db->set_histogram_tag("TopSites"); | 456 db->set_histogram_tag("TopSites"); |
| 376 db->set_page_size(4096); | 457 db->set_page_size(4096); |
| 377 db->set_cache_size(32); | 458 db->set_cache_size(32); |
| 378 | 459 |
| 379 if (!db->Open(db_name)) { | 460 if (!db->Open(db_name)) { |
| 380 LOG(ERROR) << db->GetErrorMessage(); | 461 LOG(ERROR) << db->GetErrorMessage(); |
| 381 return NULL; | 462 return NULL; |
| 382 } | 463 } |
| 383 | 464 |
| 384 return db.release(); | 465 return db.release(); |
| 385 } | 466 } |
| 386 | 467 |
| 387 } // namespace history | 468 } // namespace history |
| OLD | NEW |