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 |