OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 "webkit/quota/quota_database.h" | 5 #include "webkit/quota/quota_database.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 | 8 |
9 #include "app/sql/connection.h" | 9 #include "app/sql/connection.h" |
10 #include "app/sql/diagnostic_error_delegate.h" | 10 #include "app/sql/diagnostic_error_delegate.h" |
11 #include "app/sql/meta_table.h" | 11 #include "app/sql/meta_table.h" |
12 #include "app/sql/statement.h" | 12 #include "app/sql/statement.h" |
13 #include "app/sql/transaction.h" | 13 #include "app/sql/transaction.h" |
14 #include "base/auto_reset.h" | 14 #include "base/auto_reset.h" |
15 #include "base/bind.h" | |
16 #include "base/file_util.h" | 15 #include "base/file_util.h" |
17 #include "base/time.h" | 16 #include "base/time.h" |
18 #include "googleurl/src/gurl.h" | 17 #include "googleurl/src/gurl.h" |
19 #include "webkit/quota/special_storage_policy.h" | 18 #include "webkit/quota/special_storage_policy.h" |
20 | 19 |
21 namespace quota { | |
22 namespace { | 20 namespace { |
23 | 21 |
24 // Definitions for database schema. | 22 // Definitions for database schema. |
25 | 23 |
26 const int kCurrentVersion = 3; | 24 const int kCurrentVersion = 2; |
27 const int kCompatibleVersion = 2; | 25 const int kCompatibleVersion = 2; |
28 | 26 |
| 27 const char kOriginsTable[] = "Origins"; |
29 const char kHostQuotaTable[] = "HostQuotaTable"; | 28 const char kHostQuotaTable[] = "HostQuotaTable"; |
30 const char kOriginInfoTable[] = "OriginInfoTable"; | 29 const char kOriginLastAccessTable[] = "OriginLastAccessTable"; |
31 const char kGlobalQuotaKeyPrefix[] = "GlobalQuota-"; | 30 const char kGlobalQuotaKeyPrefix[] = "GlobalQuota-"; |
32 const char kIsOriginTableBootstrapped[] = "IsOriginTableBootstrapped"; | 31 const char kIsOriginTableBootstrapped[] = "IsOriginTableBootstrapped"; |
33 | 32 |
| 33 const struct { |
| 34 const char* table_name; |
| 35 const char* columns; |
| 36 } kTables[] = { |
| 37 { kHostQuotaTable, |
| 38 "(host TEXT NOT NULL," |
| 39 " type INTEGER NOT NULL," |
| 40 " quota INTEGER," |
| 41 " UNIQUE(host, type))" }, |
| 42 { kOriginLastAccessTable, |
| 43 "(origin TEXT NOT NULL," |
| 44 " type INTEGER NOT NULL," |
| 45 " used_count INTEGER," |
| 46 " last_access_time INTEGER," |
| 47 " UNIQUE(origin, type))" }, |
| 48 }; |
| 49 |
| 50 const struct { |
| 51 const char* index_name; |
| 52 const char* table_name; |
| 53 const char* columns; |
| 54 bool unique; |
| 55 } kIndexes[] = { |
| 56 { "HostIndex", |
| 57 kHostQuotaTable, |
| 58 "(host)", |
| 59 false }, |
| 60 { "OriginLastAccessIndex", |
| 61 kOriginLastAccessTable, |
| 62 "(origin, last_access_time)", |
| 63 false }, |
| 64 }; |
| 65 |
| 66 const int kTableCount = ARRAYSIZE_UNSAFE(kTables); |
| 67 const int kIndexCount = ARRAYSIZE_UNSAFE(kIndexes); |
| 68 |
34 class HistogramUniquifier { | 69 class HistogramUniquifier { |
35 public: | 70 public: |
36 static const char* name() { return "Sqlite.Quota.Error"; } | 71 static const char* name() { return "Sqlite.Quota.Error"; } |
37 }; | 72 }; |
38 | 73 |
39 bool PrepareCachedStatement( | 74 bool PrepareCachedStatement( |
40 sql::Connection* db, const sql::StatementID& id, | 75 sql::Connection* db, const sql::StatementID& id, |
41 const char* sql, sql::Statement* statement) { | 76 const char* sql, sql::Statement* statement) { |
42 DCHECK(db && sql && statement); | 77 DCHECK(db && sql && statement); |
43 statement->Assign(db->GetCachedStatement(id, sql)); | 78 statement->Assign(db->GetCachedStatement(id, sql)); |
(...skipping 10 matching lines...) Expand all Loading... |
54 else if (type == quota::kStorageTypePersistent) | 89 else if (type == quota::kStorageTypePersistent) |
55 return std::string(kGlobalQuotaKeyPrefix) + "persistent"; | 90 return std::string(kGlobalQuotaKeyPrefix) + "persistent"; |
56 NOTREACHED() << "Unknown storage type " << type; | 91 NOTREACHED() << "Unknown storage type " << type; |
57 return std::string(); | 92 return std::string(); |
58 } | 93 } |
59 | 94 |
60 const int kCommitIntervalMs = 30000; | 95 const int kCommitIntervalMs = 30000; |
61 | 96 |
62 } // anonymous namespace | 97 } // anonymous namespace |
63 | 98 |
64 // static | 99 namespace quota { |
65 const QuotaDatabase::TableSchema QuotaDatabase::kTables[] = { | |
66 { kHostQuotaTable, | |
67 "(host TEXT NOT NULL," | |
68 " type INTEGER NOT NULL," | |
69 " quota INTEGER DEFAULT 0," | |
70 " UNIQUE(host, type))" }, | |
71 { kOriginInfoTable, | |
72 "(origin TEXT NOT NULL," | |
73 " type INTEGER NOT NULL," | |
74 " used_count INTEGER DEFAULT 0," | |
75 " last_access_time INTEGER DEFAULT 0," | |
76 " last_modified_time INTEGER DEFAULT 0," | |
77 " UNIQUE(origin, type))" }, | |
78 }; | |
79 | |
80 // static | |
81 const QuotaDatabase::IndexSchema QuotaDatabase::kIndexes[] = { | |
82 { "HostIndex", | |
83 kHostQuotaTable, | |
84 "(host)", | |
85 false }, | |
86 { "OriginInfoIndex", | |
87 kOriginInfoTable, | |
88 "(origin)", | |
89 false }, | |
90 { "OriginLastAccessTimeIndex", | |
91 kOriginInfoTable, | |
92 "(last_access_time)", | |
93 false }, | |
94 { "OriginLastModifiedTimeIndex", | |
95 kOriginInfoTable, | |
96 "(last_modified_time)", | |
97 false }, | |
98 }; | |
99 | |
100 struct QuotaDatabase::QuotaTableImporter { | |
101 bool Append(const QuotaTableEntry& entry) { | |
102 entries.push_back(entry); | |
103 return true; | |
104 } | |
105 std::vector<QuotaTableEntry> entries; | |
106 }; | |
107 | 100 |
108 QuotaDatabase::QuotaDatabase(const FilePath& path) | 101 QuotaDatabase::QuotaDatabase(const FilePath& path) |
109 : db_file_path_(path), | 102 : db_file_path_(path), |
110 is_recreating_(false), | 103 is_recreating_(false), |
111 is_disabled_(false) { | 104 is_disabled_(false) { |
112 } | 105 } |
113 | 106 |
114 QuotaDatabase::~QuotaDatabase() { | 107 QuotaDatabase::~QuotaDatabase() { |
115 if (db_.get()) { | 108 if (db_.get()) { |
116 db_->CommitTransaction(); | 109 db_->CommitTransaction(); |
(...skipping 29 matching lines...) Expand all Loading... |
146 return true; | 139 return true; |
147 } | 140 } |
148 | 141 |
149 bool QuotaDatabase::SetHostQuota( | 142 bool QuotaDatabase::SetHostQuota( |
150 const std::string& host, StorageType type, int64 quota) { | 143 const std::string& host, StorageType type, int64 quota) { |
151 DCHECK_GE(quota, 0); | 144 DCHECK_GE(quota, 0); |
152 if (!LazyOpen(true)) | 145 if (!LazyOpen(true)) |
153 return false; | 146 return false; |
154 | 147 |
155 sql::Statement statement; | 148 sql::Statement statement; |
156 const char* kSql = | 149 |
157 "INSERT OR REPLACE INTO HostQuotaTable" | 150 int64 dummy; |
158 " (quota, host, type)" | 151 if (GetHostQuota(host, type, &dummy)) { |
159 " VALUES (?, ?, ?)"; | 152 const char* kSql = |
160 if (!PrepareCachedStatement(db_.get(), SQL_FROM_HERE, kSql, &statement)) | 153 "UPDATE HostQuotaTable" |
161 return false; | 154 " SET quota = ?" |
| 155 " WHERE host = ? AND type = ?"; |
| 156 if (!PrepareCachedStatement(db_.get(), SQL_FROM_HERE, kSql, &statement)) |
| 157 return false; |
| 158 } else { |
| 159 const char* kSql = |
| 160 "INSERT INTO HostQuotaTable" |
| 161 " (quota, host, type)" |
| 162 " VALUES (?, ?, ?)"; |
| 163 if (!PrepareCachedStatement(db_.get(), SQL_FROM_HERE, kSql, &statement)) |
| 164 return false; |
| 165 } |
162 | 166 |
163 statement.BindInt64(0, quota); | 167 statement.BindInt64(0, quota); |
164 statement.BindString(1, host); | 168 statement.BindString(1, host); |
165 statement.BindInt(2, static_cast<int>(type)); | 169 statement.BindInt(2, static_cast<int>(type)); |
166 if (!statement.Run()) | 170 if (!statement.Run()) |
167 return false; | 171 return false; |
168 | 172 |
169 ScheduleCommit(); | 173 ScheduleCommit(); |
170 return true; | 174 return true; |
171 } | 175 } |
172 | 176 |
173 bool QuotaDatabase::SetOriginLastAccessTime( | 177 bool QuotaDatabase::SetOriginLastAccessTime( |
174 const GURL& origin, StorageType type, base::Time last_access_time) { | 178 const GURL& origin, StorageType type, base::Time last_access_time) { |
175 if (!LazyOpen(true)) | 179 if (!LazyOpen(true)) |
176 return false; | 180 return false; |
177 | 181 |
178 sql::Statement statement; | 182 sql::Statement statement; |
179 | 183 |
180 int used_count = 1; | 184 int used_count = 1; |
181 if (FindOriginUsedCount(origin, type, &used_count)) { | 185 if (FindOriginUsedCount(origin, type, &used_count)) { |
182 ++used_count; | 186 ++used_count; |
183 const char* kSql = | 187 const char* kSql = |
184 "UPDATE OriginInfoTable" | 188 "UPDATE OriginLastAccessTable" |
185 " SET used_count = ?, last_access_time = ?" | 189 " SET used_count = ?, last_access_time = ?" |
186 " WHERE origin = ? AND type = ?"; | 190 " WHERE origin = ? AND type = ?"; |
187 if (!PrepareCachedStatement(db_.get(), SQL_FROM_HERE, kSql, &statement)) | 191 if (!PrepareCachedStatement(db_.get(), SQL_FROM_HERE, kSql, &statement)) |
188 return false; | 192 return false; |
189 } else { | 193 } else { |
190 const char* kSql = | 194 const char* kSql = |
191 "INSERT INTO OriginInfoTable" | 195 "INSERT INTO OriginLastAccessTable" |
192 " (used_count, last_access_time, origin, type)" | 196 " (used_count, last_access_time, origin, type)" |
193 " VALUES (?, ?, ?, ?)"; | 197 " VALUES (?, ?, ?, ?)"; |
194 if (!PrepareCachedStatement(db_.get(), SQL_FROM_HERE, kSql, &statement)) | 198 if (!PrepareCachedStatement(db_.get(), SQL_FROM_HERE, kSql, &statement)) |
195 return false; | 199 return false; |
196 } | 200 } |
197 | 201 |
198 statement.BindInt(0, used_count); | 202 statement.BindInt(0, used_count); |
199 statement.BindInt64(1, last_access_time.ToInternalValue()); | 203 statement.BindInt64(1, last_access_time.ToInternalValue()); |
200 statement.BindString(2, origin.spec()); | 204 statement.BindString(2, origin.spec()); |
201 statement.BindInt(3, static_cast<int>(type)); | 205 statement.BindInt(3, static_cast<int>(type)); |
202 if (!statement.Run()) | 206 if (!statement.Run()) |
203 return false; | 207 return false; |
204 | 208 |
205 ScheduleCommit(); | 209 ScheduleCommit(); |
206 return true; | 210 return true; |
207 } | 211 } |
208 | 212 |
209 bool QuotaDatabase::SetOriginLastModifiedTime( | 213 bool QuotaDatabase::RegisterOrigins(const std::set<GURL>& origins, |
210 const GURL& origin, StorageType type, base::Time last_modified_time) { | 214 StorageType type, |
211 if (!LazyOpen(true)) | 215 base::Time last_access_time) { |
212 return false; | |
213 | |
214 sql::Statement statement; | |
215 | |
216 int dummy; | |
217 if (FindOriginUsedCount(origin, type, &dummy)) { | |
218 const char* kSql = | |
219 "UPDATE OriginInfoTable" | |
220 " SET last_modified_time = ?" | |
221 " WHERE origin = ? AND type = ?"; | |
222 if (!PrepareCachedStatement(db_.get(), SQL_FROM_HERE, kSql, &statement)) | |
223 return false; | |
224 } else { | |
225 const char* kSql = | |
226 "INSERT INTO OriginInfoTable" | |
227 " (last_modified_time, origin, type) VALUES (?, ?, ?)"; | |
228 if (!PrepareCachedStatement(db_.get(), SQL_FROM_HERE, kSql, &statement)) | |
229 return false; | |
230 } | |
231 | |
232 statement.BindInt64(0, last_modified_time.ToInternalValue()); | |
233 statement.BindString(1, origin.spec()); | |
234 statement.BindInt(2, static_cast<int>(type)); | |
235 if (!statement.Run()) | |
236 return false; | |
237 | |
238 ScheduleCommit(); | |
239 return true; | |
240 } | |
241 | |
242 bool QuotaDatabase::RegisterInitialOriginInfo( | |
243 const std::set<GURL>& origins, StorageType type) { | |
244 if (!LazyOpen(true)) | 216 if (!LazyOpen(true)) |
245 return false; | 217 return false; |
246 | 218 |
247 typedef std::set<GURL>::const_iterator itr_type; | 219 typedef std::set<GURL>::const_iterator itr_type; |
248 for (itr_type itr = origins.begin(), end = origins.end(); | 220 for (itr_type itr = origins.begin(), end = origins.end(); |
249 itr != end; ++itr) { | 221 itr != end; ++itr) { |
250 const char* kSql = | 222 const char* kSql = |
251 "INSERT OR IGNORE INTO OriginInfoTable" | 223 "INSERT OR IGNORE INTO OriginLastAccessTable" |
252 " (origin, type) VALUES (?, ?)"; | 224 " (used_count, last_access_time, origin, type)" |
| 225 " VALUES (?, ?, ?, ?)"; |
253 sql::Statement statement; | 226 sql::Statement statement; |
254 if (!PrepareCachedStatement(db_.get(), SQL_FROM_HERE, kSql, &statement)) | 227 if (!PrepareCachedStatement(db_.get(), SQL_FROM_HERE, kSql, &statement)) |
255 return false; | 228 return false; |
256 | 229 |
257 statement.BindString(0, itr->spec()); | 230 statement.BindInt(0, 0); // used_count |
258 statement.BindInt(1, static_cast<int>(type)); | 231 statement.BindInt64(1, last_access_time.ToInternalValue()); |
| 232 statement.BindString(2, itr->spec()); |
| 233 statement.BindInt(3, static_cast<int>(type)); |
259 if (!statement.Run()) | 234 if (!statement.Run()) |
260 return false; | 235 return false; |
261 } | 236 } |
262 | 237 |
263 ScheduleCommit(); | 238 ScheduleCommit(); |
264 return true; | 239 return true; |
265 } | 240 } |
266 | 241 |
267 bool QuotaDatabase::DeleteHostQuota( | 242 bool QuotaDatabase::DeleteHostQuota( |
268 const std::string& host, StorageType type) { | 243 const std::string& host, StorageType type) { |
(...skipping 10 matching lines...) Expand all Loading... |
279 | 254 |
280 statement.BindString(0, host); | 255 statement.BindString(0, host); |
281 statement.BindInt(1, static_cast<int>(type)); | 256 statement.BindInt(1, static_cast<int>(type)); |
282 if (!statement.Run()) | 257 if (!statement.Run()) |
283 return false; | 258 return false; |
284 | 259 |
285 ScheduleCommit(); | 260 ScheduleCommit(); |
286 return true; | 261 return true; |
287 } | 262 } |
288 | 263 |
289 bool QuotaDatabase::DeleteOriginInfo( | 264 bool QuotaDatabase::DeleteOriginLastAccessTime( |
290 const GURL& origin, StorageType type) { | 265 const GURL& origin, StorageType type) { |
291 if (!LazyOpen(false)) | 266 if (!LazyOpen(false)) |
292 return false; | 267 return false; |
293 | 268 |
294 const char* kSql = | 269 const char* kSql = |
295 "DELETE FROM OriginInfoTable" | 270 "DELETE FROM OriginLastAccessTable" |
296 " WHERE origin = ? AND type = ?"; | 271 " WHERE origin = ? AND type = ?"; |
297 | 272 |
298 sql::Statement statement; | 273 sql::Statement statement; |
299 if (!PrepareCachedStatement(db_.get(), SQL_FROM_HERE, kSql, &statement)) | 274 if (!PrepareCachedStatement(db_.get(), SQL_FROM_HERE, kSql, &statement)) |
300 return false; | 275 return false; |
301 | 276 |
302 statement.BindString(0, origin.spec()); | 277 statement.BindString(0, origin.spec()); |
303 statement.BindInt(1, static_cast<int>(type)); | 278 statement.BindInt(1, static_cast<int>(type)); |
304 if (!statement.Run()) | 279 if (!statement.Run()) |
305 return false; | 280 return false; |
(...skipping 16 matching lines...) Expand all Loading... |
322 | 297 |
323 bool QuotaDatabase::GetLRUOrigin( | 298 bool QuotaDatabase::GetLRUOrigin( |
324 StorageType type, | 299 StorageType type, |
325 const std::set<GURL>& exceptions, | 300 const std::set<GURL>& exceptions, |
326 SpecialStoragePolicy* special_storage_policy, | 301 SpecialStoragePolicy* special_storage_policy, |
327 GURL* origin) { | 302 GURL* origin) { |
328 DCHECK(origin); | 303 DCHECK(origin); |
329 if (!LazyOpen(false)) | 304 if (!LazyOpen(false)) |
330 return false; | 305 return false; |
331 | 306 |
332 const char* kSql = "SELECT origin FROM OriginInfoTable" | 307 const char* kSql = "SELECT origin FROM OriginLastAccessTable" |
333 " WHERE type = ?" | 308 " WHERE type = ?" |
334 " ORDER BY last_access_time ASC"; | 309 " ORDER BY last_access_time ASC"; |
335 | 310 |
336 sql::Statement statement; | 311 sql::Statement statement; |
337 if (!PrepareCachedStatement(db_.get(), SQL_FROM_HERE, kSql, &statement)) | 312 if (!PrepareCachedStatement(db_.get(), SQL_FROM_HERE, kSql, &statement)) |
338 return false; | 313 return false; |
339 statement.BindInt(0, static_cast<int>(type)); | 314 statement.BindInt(0, static_cast<int>(type)); |
340 | 315 |
341 while (statement.Step()) { | 316 while (statement.Step()) { |
342 GURL url(statement.ColumnString(0)); | 317 GURL url(statement.ColumnString(0)); |
343 if (exceptions.find(url) != exceptions.end()) | 318 if (exceptions.find(url) != exceptions.end()) |
344 continue; | 319 continue; |
345 if (special_storage_policy && | 320 if (special_storage_policy && |
346 special_storage_policy->IsStorageUnlimited(url)) | 321 special_storage_policy->IsStorageUnlimited(url)) |
347 continue; | 322 continue; |
348 *origin = url; | 323 *origin = url; |
349 return true; | 324 return true; |
350 } | 325 } |
351 | 326 |
352 *origin = GURL(); | 327 *origin = GURL(); |
353 return statement.Succeeded(); | 328 return statement.Succeeded(); |
354 } | 329 } |
355 | 330 |
356 bool QuotaDatabase::GetOriginsModifiedSince( | |
357 StorageType type, std::set<GURL>* origins, base::Time modified_since) { | |
358 DCHECK(origins); | |
359 if (!LazyOpen(false)) | |
360 return false; | |
361 | |
362 const char* kSql = "SELECT origin FROM OriginInfoTable" | |
363 " WHERE type = ? AND last_modified_time > ?"; | |
364 | |
365 sql::Statement statement; | |
366 if (!PrepareCachedStatement(db_.get(), SQL_FROM_HERE, kSql, &statement)) | |
367 return false; | |
368 statement.BindInt(0, static_cast<int>(type)); | |
369 statement.BindInt64(1, modified_since.ToInternalValue()); | |
370 | |
371 origins->clear(); | |
372 while (statement.Step()) | |
373 origins->insert(GURL(statement.ColumnString(0))); | |
374 | |
375 return statement.Succeeded(); | |
376 } | |
377 | |
378 bool QuotaDatabase::IsOriginDatabaseBootstrapped() { | 331 bool QuotaDatabase::IsOriginDatabaseBootstrapped() { |
379 if (!LazyOpen(true)) | 332 if (!LazyOpen(true)) |
380 return false; | 333 return false; |
381 | 334 |
382 int flag = 0; | 335 int flag = 0; |
383 return meta_table_->GetValue(kIsOriginTableBootstrapped, &flag) && flag; | 336 return meta_table_->GetValue(kIsOriginTableBootstrapped, &flag) && flag; |
384 } | 337 } |
385 | 338 |
386 bool QuotaDatabase::SetOriginDatabaseBootstrapped(bool bootstrap_flag) { | 339 bool QuotaDatabase::SetOriginDatabaseBootstrapped(bool bootstrap_flag) { |
387 if (!LazyOpen(true)) | 340 if (!LazyOpen(true)) |
388 return false; | 341 return false; |
389 | 342 |
390 return meta_table_->SetValue(kIsOriginTableBootstrapped, bootstrap_flag); | 343 return meta_table_->SetValue(kIsOriginTableBootstrapped, bootstrap_flag); |
391 } | 344 } |
392 | 345 |
393 void QuotaDatabase::Commit() { | 346 void QuotaDatabase::Commit() { |
394 if (!db_.get()) | 347 if (!db_.get()) |
395 return; | 348 return; |
396 | 349 |
397 if (timer_.IsRunning()) | 350 // Note: for now this will be called only by ScheduleCommit, but when it |
398 timer_.Stop(); | 351 // becomes untrue we should call timer_.Stop() here. |
| 352 DCHECK(!timer_.IsRunning()); |
399 | 353 |
400 db_->CommitTransaction(); | 354 db_->CommitTransaction(); |
401 db_->BeginTransaction(); | 355 db_->BeginTransaction(); |
402 } | 356 } |
403 | 357 |
404 void QuotaDatabase::ScheduleCommit() { | 358 void QuotaDatabase::ScheduleCommit() { |
405 if (timer_.IsRunning()) | 359 if (timer_.IsRunning()) |
406 return; | 360 return; |
407 timer_.Start(base::TimeDelta::FromMilliseconds(kCommitIntervalMs), this, | 361 timer_.Start(base::TimeDelta::FromMilliseconds(kCommitIntervalMs), this, |
408 &QuotaDatabase::Commit); | 362 &QuotaDatabase::Commit); |
409 } | 363 } |
410 | 364 |
411 bool QuotaDatabase::FindOriginUsedCount( | 365 bool QuotaDatabase::FindOriginUsedCount( |
412 const GURL& origin, StorageType type, int* used_count) { | 366 const GURL& origin, StorageType type, int* used_count) { |
413 DCHECK(used_count); | 367 DCHECK(used_count); |
414 if (!LazyOpen(false)) | 368 if (!LazyOpen(false)) |
415 return false; | 369 return false; |
416 | 370 |
417 const char* kSql = | 371 const char* kSql = |
418 "SELECT used_count FROM OriginInfoTable" | 372 "SELECT used_count FROM OriginLastAccessTable" |
419 " WHERE origin = ? AND type = ?"; | 373 " WHERE origin = ? AND type = ?"; |
420 | 374 |
421 sql::Statement statement; | 375 sql::Statement statement; |
422 if (!PrepareCachedStatement(db_.get(), SQL_FROM_HERE, kSql, &statement)) | 376 if (!PrepareCachedStatement(db_.get(), SQL_FROM_HERE, kSql, &statement)) |
423 return false; | 377 return false; |
424 | 378 |
425 statement.BindString(0, origin.spec()); | 379 statement.BindString(0, origin.spec()); |
426 statement.BindInt(1, static_cast<int>(type)); | 380 statement.BindInt(1, static_cast<int>(type)); |
427 if (!statement.Step() || !statement.Succeeded()) | 381 if (!statement.Step() || !statement.Succeeded()) |
428 return false; | 382 return false; |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
468 return false; | 422 return false; |
469 } | 423 } |
470 | 424 |
471 // Start a long-running transaction. | 425 // Start a long-running transaction. |
472 db_->BeginTransaction(); | 426 db_->BeginTransaction(); |
473 | 427 |
474 return true; | 428 return true; |
475 } | 429 } |
476 | 430 |
477 bool QuotaDatabase::EnsureDatabaseVersion() { | 431 bool QuotaDatabase::EnsureDatabaseVersion() { |
478 static const size_t kTableCount = ARRAYSIZE_UNSAFE(kTables); | |
479 static const size_t kIndexCount = ARRAYSIZE_UNSAFE(kIndexes); | |
480 if (!sql::MetaTable::DoesTableExist(db_.get())) | 432 if (!sql::MetaTable::DoesTableExist(db_.get())) |
481 return CreateSchema(db_.get(), meta_table_.get(), | 433 return CreateSchema(); |
482 kCurrentVersion, kCompatibleVersion, | |
483 kTables, kTableCount, | |
484 kIndexes, kIndexCount); | |
485 | 434 |
486 if (!meta_table_->Init(db_.get(), kCurrentVersion, kCompatibleVersion)) | 435 if (!meta_table_->Init(db_.get(), kCurrentVersion, kCompatibleVersion)) |
487 return false; | 436 return false; |
488 | 437 |
489 if (meta_table_->GetCompatibleVersionNumber() > kCurrentVersion) { | 438 if (meta_table_->GetCompatibleVersionNumber() > kCurrentVersion) { |
490 LOG(WARNING) << "Quota database is too new."; | 439 LOG(WARNING) << "Quota database is too new."; |
491 return false; | 440 return false; |
492 } | 441 } |
493 | 442 |
494 if (meta_table_->GetVersionNumber() < kCurrentVersion) { | 443 if (meta_table_->GetVersionNumber() < kCurrentVersion) { |
495 if (!UpgradeSchema(meta_table_->GetVersionNumber())) | 444 // TODO(kinuko): Support schema upgrade. |
496 return ResetSchema(); | 445 return ResetSchema(); |
497 } | 446 } |
498 | 447 |
499 #ifndef NDEBUG | 448 #ifndef NDEBUG |
500 DCHECK(sql::MetaTable::DoesTableExist(db_.get())); | 449 DCHECK(sql::MetaTable::DoesTableExist(db_.get())); |
501 for (size_t i = 0; i < kTableCount; ++i) { | 450 for (int i = 0; i < kTableCount; ++i) { |
502 DCHECK(db_->DoesTableExist(kTables[i].table_name)); | 451 DCHECK(db_->DoesTableExist(kTables[i].table_name)); |
503 } | 452 } |
504 #endif | 453 #endif |
505 | 454 |
506 return true; | 455 return true; |
507 } | 456 } |
508 | 457 |
509 // static | 458 bool QuotaDatabase::CreateSchema() { |
510 bool QuotaDatabase::CreateSchema( | |
511 sql::Connection* database, | |
512 sql::MetaTable* meta_table, | |
513 int schema_version, int compatible_version, | |
514 const TableSchema* tables, size_t tables_size, | |
515 const IndexSchema* indexes, size_t indexes_size) { | |
516 // TODO(kinuko): Factor out the common code to create databases. | 459 // TODO(kinuko): Factor out the common code to create databases. |
517 sql::Transaction transaction(database); | 460 sql::Transaction transaction(db_.get()); |
518 if (!transaction.Begin()) | 461 if (!transaction.Begin()) |
519 return false; | 462 return false; |
520 | 463 |
521 if (!meta_table->Init(database, schema_version, compatible_version)) | 464 if (!meta_table_->Init(db_.get(), kCurrentVersion, kCompatibleVersion)) |
522 return false; | 465 return false; |
523 | 466 |
524 for (size_t i = 0; i < tables_size; ++i) { | 467 for (int i = 0; i < kTableCount; ++i) { |
525 std::string sql("CREATE TABLE "); | 468 std::string sql("CREATE TABLE "); |
526 sql += tables[i].table_name; | 469 sql += kTables[i].table_name; |
527 sql += tables[i].columns; | 470 sql += kTables[i].columns; |
528 if (!database->Execute(sql.c_str())) { | 471 if (!db_->Execute(sql.c_str())) { |
529 VLOG(1) << "Failed to execute " << sql; | 472 VLOG(1) << "Failed to execute " << sql; |
530 return false; | 473 return false; |
531 } | 474 } |
532 } | 475 } |
533 | 476 |
534 for (size_t i = 0; i < indexes_size; ++i) { | 477 for (int i = 0; i < kIndexCount; ++i) { |
535 std::string sql; | 478 std::string sql; |
536 if (indexes[i].unique) | 479 if (kIndexes[i].unique) |
537 sql += "CREATE UNIQUE INDEX "; | 480 sql += "CREATE UNIQUE INDEX "; |
538 else | 481 else |
539 sql += "CREATE INDEX "; | 482 sql += "CREATE INDEX "; |
540 sql += indexes[i].index_name; | 483 sql += kIndexes[i].index_name; |
541 sql += " ON "; | 484 sql += " ON "; |
542 sql += indexes[i].table_name; | 485 sql += kIndexes[i].table_name; |
543 sql += indexes[i].columns; | 486 sql += kIndexes[i].columns; |
544 if (!database->Execute(sql.c_str())) { | 487 if (!db_->Execute(sql.c_str())) { |
545 VLOG(1) << "Failed to execute " << sql; | 488 VLOG(1) << "Failed to execute " << sql; |
546 return false; | 489 return false; |
547 } | 490 } |
548 } | 491 } |
549 | 492 |
550 return transaction.Commit(); | 493 return transaction.Commit(); |
551 } | 494 } |
552 | 495 |
553 bool QuotaDatabase::ResetSchema() { | 496 bool QuotaDatabase::ResetSchema() { |
554 DCHECK(!db_file_path_.empty()); | 497 DCHECK(!db_file_path_.empty()); |
(...skipping 11 matching lines...) Expand all Loading... |
566 return false; | 509 return false; |
567 | 510 |
568 // So we can't go recursive. | 511 // So we can't go recursive. |
569 if (is_recreating_) | 512 if (is_recreating_) |
570 return false; | 513 return false; |
571 | 514 |
572 AutoReset<bool> auto_reset(&is_recreating_, true); | 515 AutoReset<bool> auto_reset(&is_recreating_, true); |
573 return LazyOpen(true); | 516 return LazyOpen(true); |
574 } | 517 } |
575 | 518 |
576 bool QuotaDatabase::UpgradeSchema(int current_version) { | |
577 if (current_version == 2) { | |
578 QuotaTableImporter importer; | |
579 typedef std::vector<QuotaTableEntry> QuotaTableEntries; | |
580 if (!DumpQuotaTable(new QuotaTableCallback(base::Bind( | |
581 &QuotaTableImporter::Append, base::Unretained(&importer))))) | |
582 return false; | |
583 ResetSchema(); | |
584 for (QuotaTableEntries::const_iterator iter = importer.entries.begin(); | |
585 iter != importer.entries.end(); ++iter) { | |
586 if (!SetHostQuota(iter->host, iter->type, iter->quota)) | |
587 return false; | |
588 } | |
589 Commit(); | |
590 return true; | |
591 } | |
592 return false; | |
593 } | |
594 | |
595 bool QuotaDatabase::DumpQuotaTable(QuotaTableCallback* callback) { | 519 bool QuotaDatabase::DumpQuotaTable(QuotaTableCallback* callback) { |
596 scoped_ptr<QuotaTableCallback> callback_deleter(callback); | 520 scoped_ptr<QuotaTableCallback> callback_deleter(callback); |
597 if (!LazyOpen(true)) | 521 if (!LazyOpen(true)) |
598 return false; | 522 return false; |
599 | 523 |
600 const char* kSql = "SELECT * FROM HostQuotaTable"; | 524 const char* kSql = "SELECT * FROM HostQuotaTable"; |
601 sql::Statement statement; | 525 sql::Statement statement; |
602 if (!PrepareCachedStatement(db_.get(), SQL_FROM_HERE, kSql, &statement)) | 526 if (!PrepareCachedStatement(db_.get(), SQL_FROM_HERE, kSql, &statement)) |
603 return false; | 527 return false; |
604 | 528 |
605 while (statement.Step()) { | 529 while (statement.Step()) { |
606 QuotaTableEntry entry = { | 530 QuotaTableEntry entry = { |
607 statement.ColumnString(0), | 531 statement.ColumnString(0), |
608 static_cast<StorageType>(statement.ColumnInt(1)), | 532 static_cast<StorageType>(statement.ColumnInt(1)), |
609 statement.ColumnInt64(2) | 533 statement.ColumnInt64(2) |
610 }; | 534 }; |
611 | 535 |
612 if (!callback->Run(entry)) | 536 if (!callback->Run(entry)) |
613 return true; | 537 return true; |
614 } | 538 } |
615 | 539 |
616 return statement.Succeeded(); | 540 return statement.Succeeded(); |
617 } | 541 } |
618 | 542 |
619 bool QuotaDatabase::DumpOriginInfoTable( | 543 bool QuotaDatabase::DumpLastAccessTimeTable( |
620 OriginInfoTableCallback* callback) { | 544 LastAccessTimeTableCallback* callback) { |
621 scoped_ptr<OriginInfoTableCallback> callback_deleter(callback); | 545 scoped_ptr<LastAccessTimeTableCallback> callback_deleter(callback); |
622 | 546 |
623 if (!LazyOpen(true)) | 547 if (!LazyOpen(true)) |
624 return false; | 548 return false; |
625 | 549 |
626 const char* kSql = "SELECT * FROM OriginInfoTable"; | 550 const char* kSql = "SELECT * FROM OriginLastAccessTable"; |
627 sql::Statement statement; | 551 sql::Statement statement; |
628 if (!PrepareCachedStatement(db_.get(), SQL_FROM_HERE, kSql, &statement)) | 552 if (!PrepareCachedStatement(db_.get(), SQL_FROM_HERE, kSql, &statement)) |
629 return false; | 553 return false; |
630 | 554 |
631 while (statement.Step()) { | 555 while (statement.Step()) { |
632 OriginInfoTableEntry entry = { | 556 LastAccessTimeTableEntry entry = { |
633 GURL(statement.ColumnString(0)), | 557 GURL(statement.ColumnString(0)), |
634 static_cast<StorageType>(statement.ColumnInt(1)), | 558 static_cast<StorageType>(statement.ColumnInt(1)), |
635 statement.ColumnInt(2), | 559 statement.ColumnInt(2), |
636 base::Time::FromInternalValue(statement.ColumnInt64(3)), | 560 base::Time::FromInternalValue(statement.ColumnInt64(3)) |
637 base::Time::FromInternalValue(statement.ColumnInt64(4)) | |
638 }; | 561 }; |
639 | 562 |
640 if (!callback->Run(entry)) | 563 if (!callback->Run(entry)) |
641 return true; | 564 return true; |
642 } | 565 } |
643 | 566 |
644 return statement.Succeeded(); | 567 return statement.Succeeded(); |
645 } | 568 } |
646 | 569 |
647 bool operator<(const QuotaDatabase::QuotaTableEntry& lhs, | 570 bool operator<(const QuotaDatabase::QuotaTableEntry& lhs, |
648 const QuotaDatabase::QuotaTableEntry& rhs) { | 571 const QuotaDatabase::QuotaTableEntry& rhs) { |
649 if (lhs.host < rhs.host) return true; | 572 if (lhs.host < rhs.host) return true; |
650 if (rhs.host < lhs.host) return false; | 573 if (rhs.host < lhs.host) return false; |
651 if (lhs.type < rhs.type) return true; | 574 if (lhs.type < rhs.type) return true; |
652 if (rhs.type < lhs.type) return false; | 575 if (rhs.type < lhs.type) return false; |
653 return lhs.quota < rhs.quota; | 576 return lhs.quota < rhs.quota; |
654 } | 577 } |
655 | 578 |
656 bool operator<(const QuotaDatabase::OriginInfoTableEntry& lhs, | 579 bool operator<(const QuotaDatabase::LastAccessTimeTableEntry& lhs, |
657 const QuotaDatabase::OriginInfoTableEntry& rhs) { | 580 const QuotaDatabase::LastAccessTimeTableEntry& rhs) { |
658 if (lhs.origin < rhs.origin) return true; | 581 if (lhs.origin < rhs.origin) return true; |
659 if (rhs.origin < lhs.origin) return false; | 582 if (rhs.origin < lhs.origin) return false; |
660 if (lhs.type < rhs.type) return true; | 583 if (lhs.type < rhs.type) return true; |
661 if (rhs.type < lhs.type) return false; | 584 if (rhs.type < lhs.type) return false; |
662 if (lhs.used_count < rhs.used_count) return true; | 585 if (lhs.used_count < rhs.used_count) return true; |
663 if (rhs.used_count < lhs.used_count) return false; | 586 if (rhs.used_count < lhs.used_count) return false; |
664 return lhs.last_access_time < rhs.last_access_time; | 587 return lhs.last_access_time < rhs.last_access_time; |
665 } | 588 } |
666 | |
667 } // quota namespace | 589 } // quota namespace |
OLD | NEW |