| 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 "chrome/browser/history/download_database.h" | 5 #include "chrome/browser/history/download_database.h" |
| 6 | 6 |
| 7 #include <limits> | 7 #include <limits> |
| 8 #include <string> | 8 #include <string> |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 69 DownloadDatabase::DownloadDatabase() | 69 DownloadDatabase::DownloadDatabase() |
| 70 : owning_thread_set_(false), | 70 : owning_thread_set_(false), |
| 71 owning_thread_(0), | 71 owning_thread_(0), |
| 72 next_id_(0), | 72 next_id_(0), |
| 73 next_db_handle_(0) { | 73 next_db_handle_(0) { |
| 74 } | 74 } |
| 75 | 75 |
| 76 DownloadDatabase::~DownloadDatabase() { | 76 DownloadDatabase::~DownloadDatabase() { |
| 77 } | 77 } |
| 78 | 78 |
| 79 void DownloadDatabase::CheckThread() { | |
| 80 if (owning_thread_set_) { | |
| 81 DCHECK(owning_thread_ == base::PlatformThread::CurrentId()); | |
| 82 } else { | |
| 83 owning_thread_ = base::PlatformThread::CurrentId(); | |
| 84 owning_thread_set_ = true; | |
| 85 } | |
| 86 } | |
| 87 | |
| 88 bool DownloadDatabase::EnsureColumnExists( | 79 bool DownloadDatabase::EnsureColumnExists( |
| 89 const std::string& name, const std::string& type) { | 80 const std::string& name, const std::string& type) { |
| 90 std::string add_col = "ALTER TABLE downloads ADD COLUMN " + name + " " + type; | 81 std::string add_col = "ALTER TABLE downloads ADD COLUMN " + name + " " + type; |
| 91 return GetDB().DoesColumnExist("downloads", name.c_str()) || | 82 return GetDB().DoesColumnExist("downloads", name.c_str()) || |
| 92 GetDB().Execute(add_col.c_str()); | 83 GetDB().Execute(add_col.c_str()); |
| 93 } | 84 } |
| 94 | 85 |
| 95 bool DownloadDatabase::InitDownloadTable() { | 86 bool DownloadDatabase::InitDownloadTable() { |
| 96 CheckThread(); | |
| 97 GetMetaTable().GetValue(kNextDownloadId, &next_id_); | 87 GetMetaTable().GetValue(kNextDownloadId, &next_id_); |
| 98 if (GetDB().DoesTableExist("downloads")) { | 88 if (GetDB().DoesTableExist("downloads")) { |
| 99 return EnsureColumnExists("end_time", "INTEGER NOT NULL DEFAULT 0") && | 89 return EnsureColumnExists("end_time", "INTEGER NOT NULL DEFAULT 0") && |
| 100 EnsureColumnExists("opened", "INTEGER NOT NULL DEFAULT 0"); | 90 EnsureColumnExists("opened", "INTEGER NOT NULL DEFAULT 0"); |
| 101 } else { | 91 } else { |
| 102 return GetDB().Execute(kSchema); | 92 return GetDB().Execute(kSchema); |
| 103 } | 93 } |
| 104 } | 94 } |
| 105 | 95 |
| 106 bool DownloadDatabase::DropDownloadTable() { | 96 bool DownloadDatabase::DropDownloadTable() { |
| 107 CheckThread(); | |
| 108 return GetDB().Execute("DROP TABLE downloads"); | 97 return GetDB().Execute("DROP TABLE downloads"); |
| 109 } | 98 } |
| 110 | 99 |
| 111 void DownloadDatabase::QueryDownloads( | 100 void DownloadDatabase::QueryDownloads( |
| 112 std::vector<DownloadPersistentStoreInfo>* results) { | 101 std::vector<DownloadPersistentStoreInfo>* results) { |
| 113 CheckThread(); | |
| 114 results->clear(); | 102 results->clear(); |
| 115 if (next_db_handle_ < 1) | 103 if (next_db_handle_ < 1) |
| 116 next_db_handle_ = 1; | 104 next_db_handle_ = 1; |
| 117 std::set<DownloadID> db_handles; | 105 std::set<DownloadID> db_handles; |
| 118 | 106 |
| 119 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, | 107 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, |
| 120 "SELECT id, full_path, url, start_time, received_bytes, " | 108 "SELECT id, full_path, url, start_time, received_bytes, " |
| 121 "total_bytes, state, end_time, opened " | 109 "total_bytes, state, end_time, opened " |
| 122 "FROM downloads " | 110 "FROM downloads " |
| 123 "ORDER BY start_time")); | 111 "ORDER BY start_time")); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 138 next_db_handle_ = info.db_handle + 1; | 126 next_db_handle_ = info.db_handle + 1; |
| 139 if (!db_handles.insert(info.db_handle).second) { | 127 if (!db_handles.insert(info.db_handle).second) { |
| 140 // info.db_handle was already in db_handles. The database is corrupt. | 128 // info.db_handle was already in db_handles. The database is corrupt. |
| 141 base::debug::Alias(&info.db_handle); | 129 base::debug::Alias(&info.db_handle); |
| 142 DCHECK(false); | 130 DCHECK(false); |
| 143 } | 131 } |
| 144 } | 132 } |
| 145 } | 133 } |
| 146 | 134 |
| 147 bool DownloadDatabase::UpdateDownload(const DownloadPersistentStoreInfo& data) { | 135 bool DownloadDatabase::UpdateDownload(const DownloadPersistentStoreInfo& data) { |
| 148 CheckThread(); | |
| 149 DCHECK(data.db_handle > 0); | 136 DCHECK(data.db_handle > 0); |
| 150 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, | 137 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, |
| 151 "UPDATE downloads " | 138 "UPDATE downloads " |
| 152 "SET received_bytes=?, state=?, end_time=?, opened=? WHERE id=?")); | 139 "SET received_bytes=?, state=?, end_time=?, opened=? WHERE id=?")); |
| 153 statement.BindInt64(0, data.received_bytes); | 140 statement.BindInt64(0, data.received_bytes); |
| 154 statement.BindInt(1, data.state); | 141 statement.BindInt(1, data.state); |
| 155 statement.BindInt64(2, data.end_time.ToTimeT()); | 142 statement.BindInt64(2, data.end_time.ToTimeT()); |
| 156 statement.BindInt(3, (data.opened ? 1 : 0)); | 143 statement.BindInt(3, (data.opened ? 1 : 0)); |
| 157 statement.BindInt64(4, data.db_handle); | 144 statement.BindInt64(4, data.db_handle); |
| 158 | 145 |
| 159 return statement.Run(); | 146 return statement.Run(); |
| 160 } | 147 } |
| 161 | 148 |
| 162 bool DownloadDatabase::UpdateDownloadPath(const FilePath& path, | 149 bool DownloadDatabase::UpdateDownloadPath(const FilePath& path, |
| 163 DownloadID db_handle) { | 150 DownloadID db_handle) { |
| 164 CheckThread(); | |
| 165 DCHECK(db_handle > 0); | 151 DCHECK(db_handle > 0); |
| 166 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, | 152 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, |
| 167 "UPDATE downloads SET full_path=? WHERE id=?")); | 153 "UPDATE downloads SET full_path=? WHERE id=?")); |
| 168 BindFilePath(statement, path, 0); | 154 BindFilePath(statement, path, 0); |
| 169 statement.BindInt64(1, db_handle); | 155 statement.BindInt64(1, db_handle); |
| 170 | 156 |
| 171 return statement.Run(); | 157 return statement.Run(); |
| 172 } | 158 } |
| 173 | 159 |
| 174 bool DownloadDatabase::CleanUpInProgressEntries() { | 160 bool DownloadDatabase::CleanUpInProgressEntries() { |
| 175 CheckThread(); | |
| 176 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, | 161 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, |
| 177 "UPDATE downloads SET state=? WHERE state=?")); | 162 "UPDATE downloads SET state=? WHERE state=?")); |
| 178 statement.BindInt(0, DownloadItem::CANCELLED); | 163 statement.BindInt(0, DownloadItem::CANCELLED); |
| 179 statement.BindInt(1, DownloadItem::IN_PROGRESS); | 164 statement.BindInt(1, DownloadItem::IN_PROGRESS); |
| 180 | 165 |
| 181 return statement.Run(); | 166 return statement.Run(); |
| 182 } | 167 } |
| 183 | 168 |
| 184 int64 DownloadDatabase::CreateDownload( | 169 int64 DownloadDatabase::CreateDownload( |
| 185 const DownloadPersistentStoreInfo& info) { | 170 const DownloadPersistentStoreInfo& info) { |
| 186 CheckThread(); | |
| 187 | 171 |
| 188 if (next_db_handle_ == 0) { | 172 if (next_db_handle_ == 0) { |
| 189 // This is unlikely. All current known tests and users already call | 173 // This is unlikely. All current known tests and users already call |
| 190 // QueryDownloads() before CreateDownload(). | 174 // QueryDownloads() before CreateDownload(). |
| 191 std::vector<DownloadPersistentStoreInfo> results; | 175 std::vector<DownloadPersistentStoreInfo> results; |
| 192 QueryDownloads(&results); | 176 QueryDownloads(&results); |
| 193 CHECK_NE(0, next_db_handle_); | 177 CHECK_NE(0, next_db_handle_); |
| 194 } | 178 } |
| 195 | 179 |
| 196 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, | 180 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, |
| (...skipping 16 matching lines...) Expand all Loading... |
| 213 | 197 |
| 214 if (statement.Run()) { | 198 if (statement.Run()) { |
| 215 // TODO(benjhayden) if(info.id>next_id_){setvalue;next_id_=info.id;} | 199 // TODO(benjhayden) if(info.id>next_id_){setvalue;next_id_=info.id;} |
| 216 GetMetaTable().SetValue(kNextDownloadId, ++next_id_); | 200 GetMetaTable().SetValue(kNextDownloadId, ++next_id_); |
| 217 | 201 |
| 218 return db_handle; | 202 return db_handle; |
| 219 } | 203 } |
| 220 return 0; | 204 return 0; |
| 221 } | 205 } |
| 222 | 206 |
| 223 void DownloadDatabase::RemoveDownload(DownloadID db_handle) { | 207 void DownloadDatabase::RemoveDownloads(const std::set<DownloadID>& handles) { |
| 224 CheckThread(); | 208 base::TimeTicks started_removing = base::TimeTicks::Now(); |
| 225 | 209 for (std::set<DownloadID>::const_iterator it = handles.begin(); |
| 226 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, | 210 it != handles.end(); ++it) { |
| 227 "DELETE FROM downloads WHERE id=?")); | 211 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, |
| 228 statement.BindInt64(0, db_handle); | 212 "DELETE FROM downloads WHERE id=?")); |
| 229 | 213 statement.BindInt64(0, *it); |
| 230 statement.Run(); | 214 statement.Run(); |
| 231 } | |
| 232 | |
| 233 bool DownloadDatabase::RemoveDownloadsBetween(base::Time delete_begin, | |
| 234 base::Time delete_end) { | |
| 235 CheckThread(); | |
| 236 time_t start_time = delete_begin.ToTimeT(); | |
| 237 time_t end_time = delete_end.ToTimeT(); | |
| 238 | |
| 239 int num_downloads_deleted = -1; | |
| 240 { | |
| 241 sql::Statement count(GetDB().GetCachedStatement(SQL_FROM_HERE, | |
| 242 "SELECT count(*) FROM downloads WHERE start_time >= ? " | |
| 243 "AND start_time < ? AND (State = ? OR State = ? OR State = ?)")); | |
| 244 count.BindInt64(0, start_time); | |
| 245 count.BindInt64( | |
| 246 1, | |
| 247 end_time ? end_time : std::numeric_limits<int64>::max()); | |
| 248 count.BindInt(2, DownloadItem::COMPLETE); | |
| 249 count.BindInt(3, DownloadItem::CANCELLED); | |
| 250 count.BindInt(4, DownloadItem::INTERRUPTED); | |
| 251 if (count.Step()) | |
| 252 num_downloads_deleted = count.ColumnInt(0); | |
| 253 } | 215 } |
| 254 | 216 int num_downloads_deleted = handles.size(); // TODO(benjhayden) measure |
| 255 | |
| 256 bool success = false; | |
| 257 base::TimeTicks started_removing = base::TimeTicks::Now(); | |
| 258 { | |
| 259 // This does not use an index. We currently aren't likely to have enough | |
| 260 // downloads where an index by time will give us a lot of benefit. | |
| 261 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, | |
| 262 "DELETE FROM downloads WHERE start_time >= ? AND start_time < ? " | |
| 263 "AND (State = ? OR State = ? OR State = ?)")); | |
| 264 statement.BindInt64(0, start_time); | |
| 265 statement.BindInt64( | |
| 266 1, | |
| 267 end_time ? end_time : std::numeric_limits<int64>::max()); | |
| 268 statement.BindInt(2, DownloadItem::COMPLETE); | |
| 269 statement.BindInt(3, DownloadItem::CANCELLED); | |
| 270 statement.BindInt(4, DownloadItem::INTERRUPTED); | |
| 271 | |
| 272 success = statement.Run(); | |
| 273 } | |
| 274 | |
| 275 base::TimeTicks finished_removing = base::TimeTicks::Now(); | |
| 276 | |
| 277 if (num_downloads_deleted >= 0) { | 217 if (num_downloads_deleted >= 0) { |
| 218 base::TimeTicks finished_removing = base::TimeTicks::Now(); |
| 278 UMA_HISTOGRAM_COUNTS("Download.DatabaseRemoveDownloadsCount", | 219 UMA_HISTOGRAM_COUNTS("Download.DatabaseRemoveDownloadsCount", |
| 279 num_downloads_deleted); | 220 num_downloads_deleted); |
| 280 base::TimeDelta micros = (1000 * (finished_removing - started_removing)); | 221 base::TimeDelta micros = (1000 * (finished_removing - started_removing)); |
| 281 UMA_HISTOGRAM_TIMES("Download.DatabaseRemoveDownloadsTime", micros); | 222 UMA_HISTOGRAM_TIMES("Download.DatabaseRemoveDownloadsTime", micros); |
| 282 if (num_downloads_deleted > 0) { | 223 if (num_downloads_deleted > 0) { |
| 283 UMA_HISTOGRAM_TIMES("Download.DatabaseRemoveDownloadsTimePerRecord", | 224 UMA_HISTOGRAM_TIMES("Download.DatabaseRemoveDownloadsTimePerRecord", |
| 284 (1000 * micros) / num_downloads_deleted); | 225 (1000 * micros) / num_downloads_deleted); |
| 285 } | 226 } |
| 286 } | 227 } |
| 287 | |
| 288 return success; | |
| 289 } | 228 } |
| 290 | 229 |
| 291 } // namespace history | 230 } // namespace history |
| OLD | NEW |