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

Side by Side Diff: chrome/browser/history/download_database.cc

Issue 10915180: Make DownloadHistory observe manager, items (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: . Created 8 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
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
11 #include "base/debug/alias.h" 11 #include "base/debug/alias.h"
12 #include "base/file_path.h" 12 #include "base/file_path.h"
13 #include "base/metrics/histogram.h" 13 #include "base/metrics/histogram.h"
14 #include "base/time.h" 14 #include "base/time.h"
15 #include "base/utf_string_conversions.h" 15 #include "base/utf_string_conversions.h"
16 #include "build/build_config.h" 16 #include "build/build_config.h"
17 #include "chrome/browser/history/download_persistent_store_info.h"
17 #include "content/public/browser/browser_thread.h" 18 #include "content/public/browser/browser_thread.h"
18 #include "content/public/browser/download_item.h" 19 #include "content/public/browser/download_item.h"
19 #include "content/public/browser/download_persistent_store_info.h"
20 #include "sql/statement.h" 20 #include "sql/statement.h"
21 21
22 using content::DownloadItem; 22 using content::DownloadItem;
23 using content::DownloadPersistentStoreInfo;
24 23
25 namespace history { 24 namespace history {
26 25
26 const int64 DownloadDatabase::kUninitializedHandle = -1;
27
27 namespace { 28 namespace {
28 29
29 static const char kSchema[] = 30 static const char kSchema[] =
30 "CREATE TABLE downloads (" 31 "CREATE TABLE downloads ("
31 "id INTEGER PRIMARY KEY," // SQLite-generated primary key. 32 "id INTEGER PRIMARY KEY," // SQLite-generated primary key.
32 "full_path LONGVARCHAR NOT NULL," // Location of the download on disk. 33 "full_path LONGVARCHAR NOT NULL," // Location of the download on disk.
33 "url LONGVARCHAR NOT NULL," // URL of the downloaded file. 34 "url LONGVARCHAR NOT NULL," // URL of the downloaded file.
34 "start_time INTEGER NOT NULL," // When the download was started. 35 "start_time INTEGER NOT NULL," // When the download was started.
35 "received_bytes INTEGER NOT NULL," // Total size downloaded. 36 "received_bytes INTEGER NOT NULL," // Total size downloaded.
36 "total_bytes INTEGER NOT NULL," // Total size of the download. 37 "total_bytes INTEGER NOT NULL," // Total size of the download.
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
105 DownloadDatabase::DownloadDatabase() 106 DownloadDatabase::DownloadDatabase()
106 : owning_thread_set_(false), 107 : owning_thread_set_(false),
107 owning_thread_(0), 108 owning_thread_(0),
108 next_id_(0), 109 next_id_(0),
109 next_db_handle_(0) { 110 next_db_handle_(0) {
110 } 111 }
111 112
112 DownloadDatabase::~DownloadDatabase() { 113 DownloadDatabase::~DownloadDatabase() {
113 } 114 }
114 115
115 void DownloadDatabase::CheckThread() {
116 if (owning_thread_set_) {
117 DCHECK(owning_thread_ == base::PlatformThread::CurrentId());
118 } else {
119 owning_thread_ = base::PlatformThread::CurrentId();
120 owning_thread_set_ = true;
121 }
122 }
123
124 bool DownloadDatabase::EnsureColumnExists( 116 bool DownloadDatabase::EnsureColumnExists(
125 const std::string& name, const std::string& type) { 117 const std::string& name, const std::string& type) {
126 std::string add_col = "ALTER TABLE downloads ADD COLUMN " + name + " " + type; 118 std::string add_col = "ALTER TABLE downloads ADD COLUMN " + name + " " + type;
127 return GetDB().DoesColumnExist("downloads", name.c_str()) || 119 return GetDB().DoesColumnExist("downloads", name.c_str()) ||
128 GetDB().Execute(add_col.c_str()); 120 GetDB().Execute(add_col.c_str());
129 } 121 }
130 122
131 bool DownloadDatabase::MigrateDownloadsState() { 123 bool DownloadDatabase::MigrateDownloadsState() {
132 sql::Statement statement(GetDB().GetUniqueStatement( 124 sql::Statement statement(GetDB().GetUniqueStatement(
133 "UPDATE downloads SET state=? WHERE state=?")); 125 "UPDATE downloads SET state=? WHERE state=?"));
134 statement.BindInt(0, kStateInterrupted); 126 statement.BindInt(0, kStateInterrupted);
135 statement.BindInt(1, kStateBug140687); 127 statement.BindInt(1, kStateBug140687);
136 return statement.Run(); 128 return statement.Run();
137 } 129 }
138 130
139 bool DownloadDatabase::InitDownloadTable() { 131 bool DownloadDatabase::InitDownloadTable() {
140 CheckThread();
141 GetMetaTable().GetValue(kNextDownloadId, &next_id_); 132 GetMetaTable().GetValue(kNextDownloadId, &next_id_);
142 if (GetDB().DoesTableExist("downloads")) { 133 if (GetDB().DoesTableExist("downloads")) {
143 return EnsureColumnExists("end_time", "INTEGER NOT NULL DEFAULT 0") && 134 return EnsureColumnExists("end_time", "INTEGER NOT NULL DEFAULT 0") &&
144 EnsureColumnExists("opened", "INTEGER NOT NULL DEFAULT 0"); 135 EnsureColumnExists("opened", "INTEGER NOT NULL DEFAULT 0");
145 } else { 136 } else {
146 return GetDB().Execute(kSchema); 137 return GetDB().Execute(kSchema);
147 } 138 }
148 } 139 }
149 140
150 bool DownloadDatabase::DropDownloadTable() { 141 bool DownloadDatabase::DropDownloadTable() {
151 CheckThread();
152 return GetDB().Execute("DROP TABLE downloads"); 142 return GetDB().Execute("DROP TABLE downloads");
153 } 143 }
154 144
155 void DownloadDatabase::QueryDownloads( 145 void DownloadDatabase::QueryDownloads(
156 std::vector<DownloadPersistentStoreInfo>* results) { 146 std::vector<DownloadPersistentStoreInfo>* results) {
157 CheckThread();
158 results->clear(); 147 results->clear();
159 if (next_db_handle_ < 1) 148 if (next_db_handle_ < 1)
160 next_db_handle_ = 1; 149 next_db_handle_ = 1;
161 std::set<DownloadID> db_handles; 150 std::set<DownloadID> db_handles;
162 151
163 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, 152 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
164 "SELECT id, full_path, url, start_time, received_bytes, " 153 "SELECT id, full_path, url, start_time, received_bytes, "
165 "total_bytes, state, end_time, opened " 154 "total_bytes, state, end_time, opened "
166 "FROM downloads " 155 "FROM downloads "
167 "ORDER BY start_time")); 156 "ORDER BY start_time"));
(...skipping 19 matching lines...) Expand all
187 } 176 }
188 if (info.state == DownloadItem::MAX_DOWNLOAD_STATE) { 177 if (info.state == DownloadItem::MAX_DOWNLOAD_STATE) {
189 UMA_HISTOGRAM_COUNTS("Download.DatabaseInvalidState", state); 178 UMA_HISTOGRAM_COUNTS("Download.DatabaseInvalidState", state);
190 continue; 179 continue;
191 } 180 }
192 results->push_back(info); 181 results->push_back(info);
193 } 182 }
194 } 183 }
195 184
196 bool DownloadDatabase::UpdateDownload(const DownloadPersistentStoreInfo& data) { 185 bool DownloadDatabase::UpdateDownload(const DownloadPersistentStoreInfo& data) {
197 CheckThread();
198 DCHECK(data.db_handle > 0); 186 DCHECK(data.db_handle > 0);
199 int state = StateToInt(data.state); 187 int state = StateToInt(data.state);
200 if (state == kStateInvalid) { 188 if (state == kStateInvalid) {
201 // TODO(benjhayden) [D]CHECK instead. 189 // TODO(benjhayden) [D]CHECK instead.
202 return false; 190 return false;
203 } 191 }
204 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, 192 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
205 "UPDATE downloads " 193 "UPDATE downloads "
206 "SET received_bytes=?, state=?, end_time=?, opened=? WHERE id=?")); 194 "SET full_path=?, received_bytes=?, state=?, end_time=?, total_bytes=?, "
207 statement.BindInt64(0, data.received_bytes); 195 "opened=? WHERE id=?"));
208 statement.BindInt(1, state); 196 BindFilePath(statement, data.path, 0);
209 statement.BindInt64(2, data.end_time.ToTimeT()); 197 statement.BindInt64(1, data.received_bytes);
210 statement.BindInt(3, (data.opened ? 1 : 0)); 198 statement.BindInt(2, state);
211 statement.BindInt64(4, data.db_handle); 199 statement.BindInt64(3, data.end_time.ToTimeT());
212 200 statement.BindInt(4, data.total_bytes);
213 return statement.Run(); 201 statement.BindInt(5, (data.opened ? 1 : 0));
214 } 202 statement.BindInt64(6, data.db_handle);
215
216 bool DownloadDatabase::UpdateDownloadPath(const FilePath& path,
217 DownloadID db_handle) {
218 CheckThread();
219 DCHECK(db_handle > 0);
220 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
221 "UPDATE downloads SET full_path=? WHERE id=?"));
222 BindFilePath(statement, path, 0);
223 statement.BindInt64(1, db_handle);
224 203
225 return statement.Run(); 204 return statement.Run();
226 } 205 }
227 206
228 bool DownloadDatabase::CleanUpInProgressEntries() { 207 bool DownloadDatabase::CleanUpInProgressEntries() {
229 CheckThread();
230 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, 208 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
231 "UPDATE downloads SET state=? WHERE state=?")); 209 "UPDATE downloads SET state=? WHERE state=?"));
232 statement.BindInt(0, kStateCancelled); 210 statement.BindInt(0, kStateCancelled);
233 statement.BindInt(1, kStateInProgress); 211 statement.BindInt(1, kStateInProgress);
234 212
235 return statement.Run(); 213 return statement.Run();
236 } 214 }
237 215
238 int64 DownloadDatabase::CreateDownload( 216 int64 DownloadDatabase::CreateDownload(
239 const DownloadPersistentStoreInfo& info) { 217 const DownloadPersistentStoreInfo& info) {
240 CheckThread();
241 218
242 if (next_db_handle_ == 0) { 219 if (next_db_handle_ == 0) {
243 // This is unlikely. All current known tests and users already call 220 // This is unlikely. All current known tests and users already call
244 // QueryDownloads() before CreateDownload(). 221 // QueryDownloads() before CreateDownload().
245 std::vector<DownloadPersistentStoreInfo> results; 222 std::vector<DownloadPersistentStoreInfo> results;
246 QueryDownloads(&results); 223 QueryDownloads(&results);
247 CHECK_NE(0, next_db_handle_); 224 CHECK_NE(0, next_db_handle_);
248 } 225 }
249 226
250 int state = StateToInt(info.state); 227 int state = StateToInt(info.state);
(...skipping 20 matching lines...) Expand all
271 248
272 if (statement.Run()) { 249 if (statement.Run()) {
273 // TODO(benjhayden) if(info.id>next_id_){setvalue;next_id_=info.id;} 250 // TODO(benjhayden) if(info.id>next_id_){setvalue;next_id_=info.id;}
274 GetMetaTable().SetValue(kNextDownloadId, ++next_id_); 251 GetMetaTable().SetValue(kNextDownloadId, ++next_id_);
275 252
276 return db_handle; 253 return db_handle;
277 } 254 }
278 return 0; 255 return 0;
279 } 256 }
280 257
281 void DownloadDatabase::RemoveDownload(DownloadID db_handle) { 258 void DownloadDatabase::RemoveDownloads(const std::set<DownloadID>& handles) {
282 CheckThread(); 259 int downloads_count_before = CountDownloads();
283 260 base::TimeTicks started_removing = base::TimeTicks::Now();
284 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, 261 // HistoryBackend uses a long-running Transaction that is committed
285 "DELETE FROM downloads WHERE id=?")); 262 // periodically, so this loop doesn't actually hit the disk too hard.
286 statement.BindInt64(0, db_handle); 263 for (std::set<DownloadID>::const_iterator it = handles.begin();
287 264 it != handles.end(); ++it) {
288 statement.Run(); 265 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
289 } 266 "DELETE FROM downloads WHERE id=?"));
290 267 statement.BindInt64(0, *it);
291 bool DownloadDatabase::RemoveDownloadsBetween(base::Time delete_begin, 268 statement.Run();
292 base::Time delete_end) {
293 CheckThread();
294 time_t start_time = delete_begin.ToTimeT();
295 time_t end_time = delete_end.ToTimeT();
296
297 int num_downloads_deleted = -1;
298 {
299 sql::Statement count(GetDB().GetCachedStatement(SQL_FROM_HERE,
300 "SELECT count(*) FROM downloads WHERE start_time >= ? "
301 "AND start_time < ? AND (State = ? OR State = ? OR State = ?)"));
302 count.BindInt64(0, start_time);
303 count.BindInt64(
304 1,
305 end_time ? end_time : std::numeric_limits<int64>::max());
306 count.BindInt(2, kStateComplete);
307 count.BindInt(3, kStateCancelled);
308 count.BindInt(4, kStateInterrupted);
309 if (count.Step())
310 num_downloads_deleted = count.ColumnInt(0);
311 } 269 }
312
313
314 bool success = false;
315 base::TimeTicks started_removing = base::TimeTicks::Now();
316 {
317 // This does not use an index. We currently aren't likely to have enough
318 // downloads where an index by time will give us a lot of benefit.
319 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
320 "DELETE FROM downloads WHERE start_time >= ? AND start_time < ? "
321 "AND (State = ? OR State = ? OR State = ?)"));
322 statement.BindInt64(0, start_time);
323 statement.BindInt64(
324 1,
325 end_time ? end_time : std::numeric_limits<int64>::max());
326 statement.BindInt(2, kStateComplete);
327 statement.BindInt(3, kStateCancelled);
328 statement.BindInt(4, kStateInterrupted);
329
330 success = statement.Run();
331 }
332
333 base::TimeTicks finished_removing = base::TimeTicks::Now(); 270 base::TimeTicks finished_removing = base::TimeTicks::Now();
334 271 int downloads_count_after = CountDownloads();
272 int num_downloads_deleted = downloads_count_before - downloads_count_after;
335 if (num_downloads_deleted >= 0) { 273 if (num_downloads_deleted >= 0) {
336 UMA_HISTOGRAM_COUNTS("Download.DatabaseRemoveDownloadsCount", 274 UMA_HISTOGRAM_COUNTS("Download.DatabaseRemoveDownloadsCount",
337 num_downloads_deleted); 275 num_downloads_deleted);
338 base::TimeDelta micros = (1000 * (finished_removing - started_removing)); 276 base::TimeDelta micros = (1000 * (finished_removing - started_removing));
339 UMA_HISTOGRAM_TIMES("Download.DatabaseRemoveDownloadsTime", micros); 277 UMA_HISTOGRAM_TIMES("Download.DatabaseRemoveDownloadsTime", micros);
340 if (num_downloads_deleted > 0) { 278 if (num_downloads_deleted > 0) {
341 UMA_HISTOGRAM_TIMES("Download.DatabaseRemoveDownloadsTimePerRecord", 279 UMA_HISTOGRAM_TIMES("Download.DatabaseRemoveDownloadsTimePerRecord",
342 (1000 * micros) / num_downloads_deleted); 280 (1000 * micros) / num_downloads_deleted);
343 } 281 }
344 } 282 }
283 int num_downloads_not_deleted = handles.size() - num_downloads_deleted;
284 if (num_downloads_not_deleted >= 0) {
285 UMA_HISTOGRAM_COUNTS("Download.DatabaseRemoveDownloadsCountNotRemoved",
286 num_downloads_not_deleted);
287 }
288 }
345 289
346 return success; 290 int DownloadDatabase::CountDownloads() {
291 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
292 "SELECT count(*) from downloads"));
293 statement.Step();
294 return statement.ColumnInt(0);
347 } 295 }
348 296
349 } // namespace history 297 } // namespace history
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698