OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "webkit/browser/appcache/appcache_database.h" | |
6 | |
7 #include "base/auto_reset.h" | |
8 #include "base/bind.h" | |
9 #include "base/command_line.h" | |
10 #include "base/file_util.h" | |
11 #include "base/logging.h" | |
12 #include "base/strings/utf_string_conversions.h" | |
13 #include "sql/connection.h" | |
14 #include "sql/error_delegate_util.h" | |
15 #include "sql/meta_table.h" | |
16 #include "sql/statement.h" | |
17 #include "sql/transaction.h" | |
18 #include "webkit/browser/appcache/appcache_entry.h" | |
19 #include "webkit/browser/appcache/appcache_histograms.h" | |
20 | |
21 namespace appcache { | |
22 | |
23 // Schema ------------------------------------------------------------------- | |
24 namespace { | |
25 | |
26 #if defined(APPCACHE_USE_SIMPLE_CACHE) | |
27 const int kCurrentVersion = 6; | |
28 const int kCompatibleVersion = 6; | |
29 #else | |
30 const int kCurrentVersion = 5; | |
31 const int kCompatibleVersion = 5; | |
32 #endif | |
33 | |
34 // A mechanism to run experiments that may affect in data being persisted | |
35 // in different ways such that when the experiment is toggled on/off via | |
36 // cmd line flags, the database gets reset. The active flags are stored at | |
37 // the time of database creation and compared when reopening. If different | |
38 // the database is reset. | |
39 const char kExperimentFlagsKey[] = "ExperimentFlags"; | |
40 | |
41 const char kGroupsTable[] = "Groups"; | |
42 const char kCachesTable[] = "Caches"; | |
43 const char kEntriesTable[] = "Entries"; | |
44 const char kNamespacesTable[] = "Namespaces"; | |
45 const char kOnlineWhiteListsTable[] = "OnlineWhiteLists"; | |
46 const char kDeletableResponseIdsTable[] = "DeletableResponseIds"; | |
47 | |
48 struct TableInfo { | |
49 const char* table_name; | |
50 const char* columns; | |
51 }; | |
52 | |
53 struct IndexInfo { | |
54 const char* index_name; | |
55 const char* table_name; | |
56 const char* columns; | |
57 bool unique; | |
58 }; | |
59 | |
60 const TableInfo kTables[] = { | |
61 { kGroupsTable, | |
62 "(group_id INTEGER PRIMARY KEY," | |
63 " origin TEXT," | |
64 " manifest_url TEXT," | |
65 " creation_time INTEGER," | |
66 " last_access_time INTEGER)" }, | |
67 | |
68 { kCachesTable, | |
69 "(cache_id INTEGER PRIMARY KEY," | |
70 " group_id INTEGER," | |
71 " online_wildcard INTEGER CHECK(online_wildcard IN (0, 1))," | |
72 " update_time INTEGER," | |
73 " cache_size INTEGER)" }, // intentionally not normalized | |
74 | |
75 { kEntriesTable, | |
76 "(cache_id INTEGER," | |
77 " url TEXT," | |
78 " flags INTEGER," | |
79 " response_id INTEGER," | |
80 " response_size INTEGER)" }, | |
81 | |
82 { kNamespacesTable, | |
83 "(cache_id INTEGER," | |
84 " origin TEXT," // intentionally not normalized | |
85 " type INTEGER," | |
86 " namespace_url TEXT," | |
87 " target_url TEXT," | |
88 " is_pattern INTEGER CHECK(is_pattern IN (0, 1)))" }, | |
89 | |
90 { kOnlineWhiteListsTable, | |
91 "(cache_id INTEGER," | |
92 " namespace_url TEXT," | |
93 " is_pattern INTEGER CHECK(is_pattern IN (0, 1)))" }, | |
94 | |
95 { kDeletableResponseIdsTable, | |
96 "(response_id INTEGER NOT NULL)" }, | |
97 }; | |
98 | |
99 const IndexInfo kIndexes[] = { | |
100 { "GroupsOriginIndex", | |
101 kGroupsTable, | |
102 "(origin)", | |
103 false }, | |
104 | |
105 { "GroupsManifestIndex", | |
106 kGroupsTable, | |
107 "(manifest_url)", | |
108 true }, | |
109 | |
110 { "CachesGroupIndex", | |
111 kCachesTable, | |
112 "(group_id)", | |
113 false }, | |
114 | |
115 { "EntriesCacheIndex", | |
116 kEntriesTable, | |
117 "(cache_id)", | |
118 false }, | |
119 | |
120 { "EntriesCacheAndUrlIndex", | |
121 kEntriesTable, | |
122 "(cache_id, url)", | |
123 true }, | |
124 | |
125 { "EntriesResponseIdIndex", | |
126 kEntriesTable, | |
127 "(response_id)", | |
128 true }, | |
129 | |
130 { "NamespacesCacheIndex", | |
131 kNamespacesTable, | |
132 "(cache_id)", | |
133 false }, | |
134 | |
135 { "NamespacesOriginIndex", | |
136 kNamespacesTable, | |
137 "(origin)", | |
138 false }, | |
139 | |
140 { "NamespacesCacheAndUrlIndex", | |
141 kNamespacesTable, | |
142 "(cache_id, namespace_url)", | |
143 true }, | |
144 | |
145 { "OnlineWhiteListCacheIndex", | |
146 kOnlineWhiteListsTable, | |
147 "(cache_id)", | |
148 false }, | |
149 | |
150 { "DeletableResponsesIdIndex", | |
151 kDeletableResponseIdsTable, | |
152 "(response_id)", | |
153 true }, | |
154 }; | |
155 | |
156 const int kTableCount = ARRAYSIZE_UNSAFE(kTables); | |
157 const int kIndexCount = ARRAYSIZE_UNSAFE(kIndexes); | |
158 | |
159 bool CreateTable(sql::Connection* db, const TableInfo& info) { | |
160 std::string sql("CREATE TABLE "); | |
161 sql += info.table_name; | |
162 sql += info.columns; | |
163 return db->Execute(sql.c_str()); | |
164 } | |
165 | |
166 bool CreateIndex(sql::Connection* db, const IndexInfo& info) { | |
167 std::string sql; | |
168 if (info.unique) | |
169 sql += "CREATE UNIQUE INDEX "; | |
170 else | |
171 sql += "CREATE INDEX "; | |
172 sql += info.index_name; | |
173 sql += " ON "; | |
174 sql += info.table_name; | |
175 sql += info.columns; | |
176 return db->Execute(sql.c_str()); | |
177 } | |
178 | |
179 std::string GetActiveExperimentFlags() { | |
180 if (CommandLine::ForCurrentProcess()->HasSwitch(kEnableExecutableHandlers)) | |
181 return std::string("executableHandlersEnabled"); | |
182 return std::string(); | |
183 } | |
184 | |
185 } // anon namespace | |
186 | |
187 // AppCacheDatabase ---------------------------------------------------------- | |
188 | |
189 AppCacheDatabase::GroupRecord::GroupRecord() | |
190 : group_id(0) { | |
191 } | |
192 | |
193 AppCacheDatabase::GroupRecord::~GroupRecord() { | |
194 } | |
195 | |
196 AppCacheDatabase::NamespaceRecord::NamespaceRecord() | |
197 : cache_id(0) { | |
198 } | |
199 | |
200 AppCacheDatabase::NamespaceRecord::~NamespaceRecord() { | |
201 } | |
202 | |
203 | |
204 AppCacheDatabase::AppCacheDatabase(const base::FilePath& path) | |
205 : db_file_path_(path), | |
206 is_disabled_(false), | |
207 is_recreating_(false), | |
208 was_corruption_detected_(false) { | |
209 } | |
210 | |
211 AppCacheDatabase::~AppCacheDatabase() { | |
212 } | |
213 | |
214 void AppCacheDatabase::Disable() { | |
215 VLOG(1) << "Disabling appcache database."; | |
216 is_disabled_ = true; | |
217 ResetConnectionAndTables(); | |
218 } | |
219 | |
220 int64 AppCacheDatabase::GetOriginUsage(const GURL& origin) { | |
221 std::vector<CacheRecord> records; | |
222 if (!FindCachesForOrigin(origin, &records)) | |
223 return 0; | |
224 | |
225 int64 origin_usage = 0; | |
226 std::vector<CacheRecord>::const_iterator iter = records.begin(); | |
227 while (iter != records.end()) { | |
228 origin_usage += iter->cache_size; | |
229 ++iter; | |
230 } | |
231 return origin_usage; | |
232 } | |
233 | |
234 bool AppCacheDatabase::GetAllOriginUsage(std::map<GURL, int64>* usage_map) { | |
235 std::set<GURL> origins; | |
236 if (!FindOriginsWithGroups(&origins)) | |
237 return false; | |
238 for (std::set<GURL>::const_iterator origin = origins.begin(); | |
239 origin != origins.end(); ++origin) { | |
240 (*usage_map)[*origin] = GetOriginUsage(*origin); | |
241 } | |
242 return true; | |
243 } | |
244 | |
245 bool AppCacheDatabase::FindOriginsWithGroups(std::set<GURL>* origins) { | |
246 DCHECK(origins && origins->empty()); | |
247 if (!LazyOpen(false)) | |
248 return false; | |
249 | |
250 const char* kSql = | |
251 "SELECT DISTINCT(origin) FROM Groups"; | |
252 | |
253 sql::Statement statement(db_->GetUniqueStatement(kSql)); | |
254 | |
255 while (statement.Step()) | |
256 origins->insert(GURL(statement.ColumnString(0))); | |
257 | |
258 return statement.Succeeded(); | |
259 } | |
260 | |
261 bool AppCacheDatabase::FindLastStorageIds( | |
262 int64* last_group_id, int64* last_cache_id, int64* last_response_id, | |
263 int64* last_deletable_response_rowid) { | |
264 DCHECK(last_group_id && last_cache_id && last_response_id && | |
265 last_deletable_response_rowid); | |
266 | |
267 *last_group_id = 0; | |
268 *last_cache_id = 0; | |
269 *last_response_id = 0; | |
270 *last_deletable_response_rowid = 0; | |
271 | |
272 if (!LazyOpen(false)) | |
273 return false; | |
274 | |
275 const char* kMaxGroupIdSql = "SELECT MAX(group_id) FROM Groups"; | |
276 const char* kMaxCacheIdSql = "SELECT MAX(cache_id) FROM Caches"; | |
277 const char* kMaxResponseIdFromEntriesSql = | |
278 "SELECT MAX(response_id) FROM Entries"; | |
279 const char* kMaxResponseIdFromDeletablesSql = | |
280 "SELECT MAX(response_id) FROM DeletableResponseIds"; | |
281 const char* kMaxDeletableResponseRowIdSql = | |
282 "SELECT MAX(rowid) FROM DeletableResponseIds"; | |
283 int64 max_group_id; | |
284 int64 max_cache_id; | |
285 int64 max_response_id_from_entries; | |
286 int64 max_response_id_from_deletables; | |
287 int64 max_deletable_response_rowid; | |
288 if (!RunUniqueStatementWithInt64Result(kMaxGroupIdSql, &max_group_id) || | |
289 !RunUniqueStatementWithInt64Result(kMaxCacheIdSql, &max_cache_id) || | |
290 !RunUniqueStatementWithInt64Result(kMaxResponseIdFromEntriesSql, | |
291 &max_response_id_from_entries) || | |
292 !RunUniqueStatementWithInt64Result(kMaxResponseIdFromDeletablesSql, | |
293 &max_response_id_from_deletables) || | |
294 !RunUniqueStatementWithInt64Result(kMaxDeletableResponseRowIdSql, | |
295 &max_deletable_response_rowid)) { | |
296 return false; | |
297 } | |
298 | |
299 *last_group_id = max_group_id; | |
300 *last_cache_id = max_cache_id; | |
301 *last_response_id = std::max(max_response_id_from_entries, | |
302 max_response_id_from_deletables); | |
303 *last_deletable_response_rowid = max_deletable_response_rowid; | |
304 return true; | |
305 } | |
306 | |
307 bool AppCacheDatabase::FindGroup(int64 group_id, GroupRecord* record) { | |
308 DCHECK(record); | |
309 if (!LazyOpen(false)) | |
310 return false; | |
311 | |
312 const char* kSql = | |
313 "SELECT group_id, origin, manifest_url," | |
314 " creation_time, last_access_time" | |
315 " FROM Groups WHERE group_id = ?"; | |
316 | |
317 sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql)); | |
318 | |
319 statement.BindInt64(0, group_id); | |
320 if (!statement.Step()) | |
321 return false; | |
322 | |
323 ReadGroupRecord(statement, record); | |
324 DCHECK(record->group_id == group_id); | |
325 return true; | |
326 } | |
327 | |
328 bool AppCacheDatabase::FindGroupForManifestUrl( | |
329 const GURL& manifest_url, GroupRecord* record) { | |
330 DCHECK(record); | |
331 if (!LazyOpen(false)) | |
332 return false; | |
333 | |
334 const char* kSql = | |
335 "SELECT group_id, origin, manifest_url," | |
336 " creation_time, last_access_time" | |
337 " FROM Groups WHERE manifest_url = ?"; | |
338 | |
339 sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql)); | |
340 statement.BindString(0, manifest_url.spec()); | |
341 | |
342 if (!statement.Step()) | |
343 return false; | |
344 | |
345 ReadGroupRecord(statement, record); | |
346 DCHECK(record->manifest_url == manifest_url); | |
347 return true; | |
348 } | |
349 | |
350 bool AppCacheDatabase::FindGroupsForOrigin( | |
351 const GURL& origin, std::vector<GroupRecord>* records) { | |
352 DCHECK(records && records->empty()); | |
353 if (!LazyOpen(false)) | |
354 return false; | |
355 | |
356 const char* kSql = | |
357 "SELECT group_id, origin, manifest_url," | |
358 " creation_time, last_access_time" | |
359 " FROM Groups WHERE origin = ?"; | |
360 | |
361 sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql)); | |
362 statement.BindString(0, origin.spec()); | |
363 | |
364 while (statement.Step()) { | |
365 records->push_back(GroupRecord()); | |
366 ReadGroupRecord(statement, &records->back()); | |
367 DCHECK(records->back().origin == origin); | |
368 } | |
369 | |
370 return statement.Succeeded(); | |
371 } | |
372 | |
373 bool AppCacheDatabase::FindGroupForCache(int64 cache_id, GroupRecord* record) { | |
374 DCHECK(record); | |
375 if (!LazyOpen(false)) | |
376 return false; | |
377 | |
378 const char* kSql = | |
379 "SELECT g.group_id, g.origin, g.manifest_url," | |
380 " g.creation_time, g.last_access_time" | |
381 " FROM Groups g, Caches c" | |
382 " WHERE c.cache_id = ? AND c.group_id = g.group_id"; | |
383 | |
384 sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql)); | |
385 statement.BindInt64(0, cache_id); | |
386 | |
387 if (!statement.Step()) | |
388 return false; | |
389 | |
390 ReadGroupRecord(statement, record); | |
391 return true; | |
392 } | |
393 | |
394 bool AppCacheDatabase::UpdateGroupLastAccessTime( | |
395 int64 group_id, base::Time time) { | |
396 if (!LazyOpen(true)) | |
397 return false; | |
398 | |
399 const char* kSql = | |
400 "UPDATE Groups SET last_access_time = ? WHERE group_id = ?"; | |
401 | |
402 sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql)); | |
403 statement.BindInt64(0, time.ToInternalValue()); | |
404 statement.BindInt64(1, group_id); | |
405 | |
406 return statement.Run() && db_->GetLastChangeCount(); | |
407 } | |
408 | |
409 bool AppCacheDatabase::InsertGroup(const GroupRecord* record) { | |
410 if (!LazyOpen(true)) | |
411 return false; | |
412 | |
413 const char* kSql = | |
414 "INSERT INTO Groups" | |
415 " (group_id, origin, manifest_url, creation_time, last_access_time)" | |
416 " VALUES(?, ?, ?, ?, ?)"; | |
417 | |
418 sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql)); | |
419 statement.BindInt64(0, record->group_id); | |
420 statement.BindString(1, record->origin.spec()); | |
421 statement.BindString(2, record->manifest_url.spec()); | |
422 statement.BindInt64(3, record->creation_time.ToInternalValue()); | |
423 statement.BindInt64(4, record->last_access_time.ToInternalValue()); | |
424 | |
425 return statement.Run(); | |
426 } | |
427 | |
428 bool AppCacheDatabase::DeleteGroup(int64 group_id) { | |
429 if (!LazyOpen(false)) | |
430 return false; | |
431 | |
432 const char* kSql = | |
433 "DELETE FROM Groups WHERE group_id = ?"; | |
434 | |
435 sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql)); | |
436 statement.BindInt64(0, group_id); | |
437 | |
438 return statement.Run(); | |
439 } | |
440 | |
441 bool AppCacheDatabase::FindCache(int64 cache_id, CacheRecord* record) { | |
442 DCHECK(record); | |
443 if (!LazyOpen(false)) | |
444 return false; | |
445 | |
446 const char* kSql = | |
447 "SELECT cache_id, group_id, online_wildcard, update_time, cache_size" | |
448 " FROM Caches WHERE cache_id = ?"; | |
449 | |
450 sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql)); | |
451 statement.BindInt64(0, cache_id); | |
452 | |
453 if (!statement.Step()) | |
454 return false; | |
455 | |
456 ReadCacheRecord(statement, record); | |
457 return true; | |
458 } | |
459 | |
460 bool AppCacheDatabase::FindCacheForGroup(int64 group_id, CacheRecord* record) { | |
461 DCHECK(record); | |
462 if (!LazyOpen(false)) | |
463 return false; | |
464 | |
465 const char* kSql = | |
466 "SELECT cache_id, group_id, online_wildcard, update_time, cache_size" | |
467 " FROM Caches WHERE group_id = ?"; | |
468 | |
469 sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql)); | |
470 statement.BindInt64(0, group_id); | |
471 | |
472 if (!statement.Step()) | |
473 return false; | |
474 | |
475 ReadCacheRecord(statement, record); | |
476 return true; | |
477 } | |
478 | |
479 bool AppCacheDatabase::FindCachesForOrigin( | |
480 const GURL& origin, std::vector<CacheRecord>* records) { | |
481 DCHECK(records); | |
482 std::vector<GroupRecord> group_records; | |
483 if (!FindGroupsForOrigin(origin, &group_records)) | |
484 return false; | |
485 | |
486 CacheRecord cache_record; | |
487 std::vector<GroupRecord>::const_iterator iter = group_records.begin(); | |
488 while (iter != group_records.end()) { | |
489 if (FindCacheForGroup(iter->group_id, &cache_record)) | |
490 records->push_back(cache_record); | |
491 ++iter; | |
492 } | |
493 return true; | |
494 } | |
495 | |
496 bool AppCacheDatabase::InsertCache(const CacheRecord* record) { | |
497 if (!LazyOpen(true)) | |
498 return false; | |
499 | |
500 const char* kSql = | |
501 "INSERT INTO Caches (cache_id, group_id, online_wildcard," | |
502 " update_time, cache_size)" | |
503 " VALUES(?, ?, ?, ?, ?)"; | |
504 | |
505 sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql)); | |
506 statement.BindInt64(0, record->cache_id); | |
507 statement.BindInt64(1, record->group_id); | |
508 statement.BindBool(2, record->online_wildcard); | |
509 statement.BindInt64(3, record->update_time.ToInternalValue()); | |
510 statement.BindInt64(4, record->cache_size); | |
511 | |
512 return statement.Run(); | |
513 } | |
514 | |
515 bool AppCacheDatabase::DeleteCache(int64 cache_id) { | |
516 if (!LazyOpen(false)) | |
517 return false; | |
518 | |
519 const char* kSql = | |
520 "DELETE FROM Caches WHERE cache_id = ?"; | |
521 | |
522 sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql)); | |
523 statement.BindInt64(0, cache_id); | |
524 | |
525 return statement.Run(); | |
526 } | |
527 | |
528 bool AppCacheDatabase::FindEntriesForCache( | |
529 int64 cache_id, std::vector<EntryRecord>* records) { | |
530 DCHECK(records && records->empty()); | |
531 if (!LazyOpen(false)) | |
532 return false; | |
533 | |
534 const char* kSql = | |
535 "SELECT cache_id, url, flags, response_id, response_size FROM Entries" | |
536 " WHERE cache_id = ?"; | |
537 | |
538 sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql)); | |
539 statement.BindInt64(0, cache_id); | |
540 | |
541 while (statement.Step()) { | |
542 records->push_back(EntryRecord()); | |
543 ReadEntryRecord(statement, &records->back()); | |
544 DCHECK(records->back().cache_id == cache_id); | |
545 } | |
546 | |
547 return statement.Succeeded(); | |
548 } | |
549 | |
550 bool AppCacheDatabase::FindEntriesForUrl( | |
551 const GURL& url, std::vector<EntryRecord>* records) { | |
552 DCHECK(records && records->empty()); | |
553 if (!LazyOpen(false)) | |
554 return false; | |
555 | |
556 const char* kSql = | |
557 "SELECT cache_id, url, flags, response_id, response_size FROM Entries" | |
558 " WHERE url = ?"; | |
559 | |
560 sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql)); | |
561 statement.BindString(0, url.spec()); | |
562 | |
563 while (statement.Step()) { | |
564 records->push_back(EntryRecord()); | |
565 ReadEntryRecord(statement, &records->back()); | |
566 DCHECK(records->back().url == url); | |
567 } | |
568 | |
569 return statement.Succeeded(); | |
570 } | |
571 | |
572 bool AppCacheDatabase::FindEntry( | |
573 int64 cache_id, const GURL& url, EntryRecord* record) { | |
574 DCHECK(record); | |
575 if (!LazyOpen(false)) | |
576 return false; | |
577 | |
578 const char* kSql = | |
579 "SELECT cache_id, url, flags, response_id, response_size FROM Entries" | |
580 " WHERE cache_id = ? AND url = ?"; | |
581 | |
582 sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql)); | |
583 statement.BindInt64(0, cache_id); | |
584 statement.BindString(1, url.spec()); | |
585 | |
586 if (!statement.Step()) | |
587 return false; | |
588 | |
589 ReadEntryRecord(statement, record); | |
590 DCHECK(record->cache_id == cache_id); | |
591 DCHECK(record->url == url); | |
592 return true; | |
593 } | |
594 | |
595 bool AppCacheDatabase::InsertEntry(const EntryRecord* record) { | |
596 if (!LazyOpen(true)) | |
597 return false; | |
598 | |
599 const char* kSql = | |
600 "INSERT INTO Entries (cache_id, url, flags, response_id, response_size)" | |
601 " VALUES(?, ?, ?, ?, ?)"; | |
602 | |
603 sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql)); | |
604 statement.BindInt64(0, record->cache_id); | |
605 statement.BindString(1, record->url.spec()); | |
606 statement.BindInt(2, record->flags); | |
607 statement.BindInt64(3, record->response_id); | |
608 statement.BindInt64(4, record->response_size); | |
609 | |
610 return statement.Run(); | |
611 } | |
612 | |
613 bool AppCacheDatabase::InsertEntryRecords( | |
614 const std::vector<EntryRecord>& records) { | |
615 if (records.empty()) | |
616 return true; | |
617 sql::Transaction transaction(db_.get()); | |
618 if (!transaction.Begin()) | |
619 return false; | |
620 std::vector<EntryRecord>::const_iterator iter = records.begin(); | |
621 while (iter != records.end()) { | |
622 if (!InsertEntry(&(*iter))) | |
623 return false; | |
624 ++iter; | |
625 } | |
626 return transaction.Commit(); | |
627 } | |
628 | |
629 bool AppCacheDatabase::DeleteEntriesForCache(int64 cache_id) { | |
630 if (!LazyOpen(false)) | |
631 return false; | |
632 | |
633 const char* kSql = | |
634 "DELETE FROM Entries WHERE cache_id = ?"; | |
635 | |
636 sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql)); | |
637 statement.BindInt64(0, cache_id); | |
638 | |
639 return statement.Run(); | |
640 } | |
641 | |
642 bool AppCacheDatabase::AddEntryFlags( | |
643 const GURL& entry_url, int64 cache_id, int additional_flags) { | |
644 if (!LazyOpen(false)) | |
645 return false; | |
646 | |
647 const char* kSql = | |
648 "UPDATE Entries SET flags = flags | ? WHERE cache_id = ? AND url = ?"; | |
649 | |
650 sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql)); | |
651 statement.BindInt(0, additional_flags); | |
652 statement.BindInt64(1, cache_id); | |
653 statement.BindString(2, entry_url.spec()); | |
654 | |
655 return statement.Run() && db_->GetLastChangeCount(); | |
656 } | |
657 | |
658 bool AppCacheDatabase::FindNamespacesForOrigin( | |
659 const GURL& origin, | |
660 std::vector<NamespaceRecord>* intercepts, | |
661 std::vector<NamespaceRecord>* fallbacks) { | |
662 DCHECK(intercepts && intercepts->empty()); | |
663 DCHECK(fallbacks && fallbacks->empty()); | |
664 if (!LazyOpen(false)) | |
665 return false; | |
666 | |
667 const char* kSql = | |
668 "SELECT cache_id, origin, type, namespace_url, target_url, is_pattern" | |
669 " FROM Namespaces WHERE origin = ?"; | |
670 | |
671 sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql)); | |
672 statement.BindString(0, origin.spec()); | |
673 | |
674 ReadNamespaceRecords(&statement, intercepts, fallbacks); | |
675 | |
676 return statement.Succeeded(); | |
677 } | |
678 | |
679 bool AppCacheDatabase::FindNamespacesForCache( | |
680 int64 cache_id, | |
681 std::vector<NamespaceRecord>* intercepts, | |
682 std::vector<NamespaceRecord>* fallbacks) { | |
683 DCHECK(intercepts && intercepts->empty()); | |
684 DCHECK(fallbacks && fallbacks->empty()); | |
685 if (!LazyOpen(false)) | |
686 return false; | |
687 | |
688 const char* kSql = | |
689 "SELECT cache_id, origin, type, namespace_url, target_url, is_pattern" | |
690 " FROM Namespaces WHERE cache_id = ?"; | |
691 | |
692 sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql)); | |
693 statement.BindInt64(0, cache_id); | |
694 | |
695 ReadNamespaceRecords(&statement, intercepts, fallbacks); | |
696 | |
697 return statement.Succeeded(); | |
698 } | |
699 | |
700 bool AppCacheDatabase::InsertNamespace( | |
701 const NamespaceRecord* record) { | |
702 if (!LazyOpen(true)) | |
703 return false; | |
704 | |
705 const char* kSql = | |
706 "INSERT INTO Namespaces" | |
707 " (cache_id, origin, type, namespace_url, target_url, is_pattern)" | |
708 " VALUES (?, ?, ?, ?, ?, ?)"; | |
709 | |
710 // Note: quick and dirty storage for the 'executable' bit w/o changing | |
711 // schemas, we use the high bit of 'type' field. | |
712 int type_with_executable_bit = record->namespace_.type; | |
713 if (record->namespace_.is_executable) { | |
714 type_with_executable_bit |= 0x8000000; | |
715 DCHECK(CommandLine::ForCurrentProcess()->HasSwitch( | |
716 kEnableExecutableHandlers)); | |
717 } | |
718 | |
719 sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql)); | |
720 statement.BindInt64(0, record->cache_id); | |
721 statement.BindString(1, record->origin.spec()); | |
722 statement.BindInt(2, type_with_executable_bit); | |
723 statement.BindString(3, record->namespace_.namespace_url.spec()); | |
724 statement.BindString(4, record->namespace_.target_url.spec()); | |
725 statement.BindBool(5, record->namespace_.is_pattern); | |
726 return statement.Run(); | |
727 } | |
728 | |
729 bool AppCacheDatabase::InsertNamespaceRecords( | |
730 const std::vector<NamespaceRecord>& records) { | |
731 if (records.empty()) | |
732 return true; | |
733 sql::Transaction transaction(db_.get()); | |
734 if (!transaction.Begin()) | |
735 return false; | |
736 std::vector<NamespaceRecord>::const_iterator iter = records.begin(); | |
737 while (iter != records.end()) { | |
738 if (!InsertNamespace(&(*iter))) | |
739 return false; | |
740 ++iter; | |
741 } | |
742 return transaction.Commit(); | |
743 } | |
744 | |
745 bool AppCacheDatabase::DeleteNamespacesForCache(int64 cache_id) { | |
746 if (!LazyOpen(false)) | |
747 return false; | |
748 | |
749 const char* kSql = | |
750 "DELETE FROM Namespaces WHERE cache_id = ?"; | |
751 | |
752 sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql)); | |
753 statement.BindInt64(0, cache_id); | |
754 | |
755 return statement.Run(); | |
756 } | |
757 | |
758 bool AppCacheDatabase::FindOnlineWhiteListForCache( | |
759 int64 cache_id, std::vector<OnlineWhiteListRecord>* records) { | |
760 DCHECK(records && records->empty()); | |
761 if (!LazyOpen(false)) | |
762 return false; | |
763 | |
764 const char* kSql = | |
765 "SELECT cache_id, namespace_url, is_pattern FROM OnlineWhiteLists" | |
766 " WHERE cache_id = ?"; | |
767 | |
768 sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql)); | |
769 statement.BindInt64(0, cache_id); | |
770 | |
771 while (statement.Step()) { | |
772 records->push_back(OnlineWhiteListRecord()); | |
773 this->ReadOnlineWhiteListRecord(statement, &records->back()); | |
774 DCHECK(records->back().cache_id == cache_id); | |
775 } | |
776 return statement.Succeeded(); | |
777 } | |
778 | |
779 bool AppCacheDatabase::InsertOnlineWhiteList( | |
780 const OnlineWhiteListRecord* record) { | |
781 if (!LazyOpen(true)) | |
782 return false; | |
783 | |
784 const char* kSql = | |
785 "INSERT INTO OnlineWhiteLists (cache_id, namespace_url, is_pattern)" | |
786 " VALUES (?, ?, ?)"; | |
787 | |
788 sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql)); | |
789 statement.BindInt64(0, record->cache_id); | |
790 statement.BindString(1, record->namespace_url.spec()); | |
791 statement.BindBool(2, record->is_pattern); | |
792 | |
793 return statement.Run(); | |
794 } | |
795 | |
796 bool AppCacheDatabase::InsertOnlineWhiteListRecords( | |
797 const std::vector<OnlineWhiteListRecord>& records) { | |
798 if (records.empty()) | |
799 return true; | |
800 sql::Transaction transaction(db_.get()); | |
801 if (!transaction.Begin()) | |
802 return false; | |
803 std::vector<OnlineWhiteListRecord>::const_iterator iter = records.begin(); | |
804 while (iter != records.end()) { | |
805 if (!InsertOnlineWhiteList(&(*iter))) | |
806 return false; | |
807 ++iter; | |
808 } | |
809 return transaction.Commit(); | |
810 } | |
811 | |
812 bool AppCacheDatabase::DeleteOnlineWhiteListForCache(int64 cache_id) { | |
813 if (!LazyOpen(false)) | |
814 return false; | |
815 | |
816 const char* kSql = | |
817 "DELETE FROM OnlineWhiteLists WHERE cache_id = ?"; | |
818 | |
819 sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql)); | |
820 statement.BindInt64(0, cache_id); | |
821 | |
822 return statement.Run(); | |
823 } | |
824 | |
825 bool AppCacheDatabase::GetDeletableResponseIds( | |
826 std::vector<int64>* response_ids, int64 max_rowid, int limit) { | |
827 if (!LazyOpen(false)) | |
828 return false; | |
829 | |
830 const char* kSql = | |
831 "SELECT response_id FROM DeletableResponseIds " | |
832 " WHERE rowid <= ?" | |
833 " LIMIT ?"; | |
834 | |
835 sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql)); | |
836 statement.BindInt64(0, max_rowid); | |
837 statement.BindInt64(1, limit); | |
838 | |
839 while (statement.Step()) | |
840 response_ids->push_back(statement.ColumnInt64(0)); | |
841 return statement.Succeeded(); | |
842 } | |
843 | |
844 bool AppCacheDatabase::InsertDeletableResponseIds( | |
845 const std::vector<int64>& response_ids) { | |
846 const char* kSql = | |
847 "INSERT INTO DeletableResponseIds (response_id) VALUES (?)"; | |
848 return RunCachedStatementWithIds(SQL_FROM_HERE, kSql, response_ids); | |
849 } | |
850 | |
851 bool AppCacheDatabase::DeleteDeletableResponseIds( | |
852 const std::vector<int64>& response_ids) { | |
853 const char* kSql = | |
854 "DELETE FROM DeletableResponseIds WHERE response_id = ?"; | |
855 return RunCachedStatementWithIds(SQL_FROM_HERE, kSql, response_ids); | |
856 } | |
857 | |
858 bool AppCacheDatabase::RunCachedStatementWithIds( | |
859 const sql::StatementID& statement_id, const char* sql, | |
860 const std::vector<int64>& ids) { | |
861 DCHECK(sql); | |
862 if (!LazyOpen(true)) | |
863 return false; | |
864 | |
865 sql::Transaction transaction(db_.get()); | |
866 if (!transaction.Begin()) | |
867 return false; | |
868 | |
869 sql::Statement statement(db_->GetCachedStatement(statement_id, sql)); | |
870 | |
871 std::vector<int64>::const_iterator iter = ids.begin(); | |
872 while (iter != ids.end()) { | |
873 statement.BindInt64(0, *iter); | |
874 if (!statement.Run()) | |
875 return false; | |
876 statement.Reset(true); | |
877 ++iter; | |
878 } | |
879 | |
880 return transaction.Commit(); | |
881 } | |
882 | |
883 bool AppCacheDatabase::RunUniqueStatementWithInt64Result( | |
884 const char* sql, int64* result) { | |
885 DCHECK(sql); | |
886 sql::Statement statement(db_->GetUniqueStatement(sql)); | |
887 if (!statement.Step()) { | |
888 return false; | |
889 } | |
890 *result = statement.ColumnInt64(0); | |
891 return true; | |
892 } | |
893 | |
894 bool AppCacheDatabase::FindResponseIdsForCacheHelper( | |
895 int64 cache_id, std::vector<int64>* ids_vector, | |
896 std::set<int64>* ids_set) { | |
897 DCHECK(ids_vector || ids_set); | |
898 DCHECK(!(ids_vector && ids_set)); | |
899 if (!LazyOpen(false)) | |
900 return false; | |
901 | |
902 const char* kSql = | |
903 "SELECT response_id FROM Entries WHERE cache_id = ?"; | |
904 | |
905 sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql)); | |
906 | |
907 statement.BindInt64(0, cache_id); | |
908 while (statement.Step()) { | |
909 int64 id = statement.ColumnInt64(0); | |
910 if (ids_set) | |
911 ids_set->insert(id); | |
912 else | |
913 ids_vector->push_back(id); | |
914 } | |
915 | |
916 return statement.Succeeded(); | |
917 } | |
918 | |
919 void AppCacheDatabase::ReadGroupRecord( | |
920 const sql::Statement& statement, GroupRecord* record) { | |
921 record->group_id = statement.ColumnInt64(0); | |
922 record->origin = GURL(statement.ColumnString(1)); | |
923 record->manifest_url = GURL(statement.ColumnString(2)); | |
924 record->creation_time = | |
925 base::Time::FromInternalValue(statement.ColumnInt64(3)); | |
926 record->last_access_time = | |
927 base::Time::FromInternalValue(statement.ColumnInt64(4)); | |
928 } | |
929 | |
930 void AppCacheDatabase::ReadCacheRecord( | |
931 const sql::Statement& statement, CacheRecord* record) { | |
932 record->cache_id = statement.ColumnInt64(0); | |
933 record->group_id = statement.ColumnInt64(1); | |
934 record->online_wildcard = statement.ColumnBool(2); | |
935 record->update_time = | |
936 base::Time::FromInternalValue(statement.ColumnInt64(3)); | |
937 record->cache_size = statement.ColumnInt64(4); | |
938 } | |
939 | |
940 void AppCacheDatabase::ReadEntryRecord( | |
941 const sql::Statement& statement, EntryRecord* record) { | |
942 record->cache_id = statement.ColumnInt64(0); | |
943 record->url = GURL(statement.ColumnString(1)); | |
944 record->flags = statement.ColumnInt(2); | |
945 record->response_id = statement.ColumnInt64(3); | |
946 record->response_size = statement.ColumnInt64(4); | |
947 } | |
948 | |
949 void AppCacheDatabase::ReadNamespaceRecords( | |
950 sql::Statement* statement, | |
951 NamespaceRecordVector* intercepts, | |
952 NamespaceRecordVector* fallbacks) { | |
953 while (statement->Step()) { | |
954 AppCacheNamespaceType type = static_cast<AppCacheNamespaceType>( | |
955 statement->ColumnInt(2)); | |
956 NamespaceRecordVector* records = | |
957 (type == APPCACHE_FALLBACK_NAMESPACE) ? fallbacks : intercepts; | |
958 records->push_back(NamespaceRecord()); | |
959 ReadNamespaceRecord(statement, &records->back()); | |
960 } | |
961 } | |
962 | |
963 void AppCacheDatabase::ReadNamespaceRecord( | |
964 const sql::Statement* statement, NamespaceRecord* record) { | |
965 record->cache_id = statement->ColumnInt64(0); | |
966 record->origin = GURL(statement->ColumnString(1)); | |
967 int type_with_executable_bit = statement->ColumnInt(2); | |
968 record->namespace_.namespace_url = GURL(statement->ColumnString(3)); | |
969 record->namespace_.target_url = GURL(statement->ColumnString(4)); | |
970 record->namespace_.is_pattern = statement->ColumnBool(5); | |
971 | |
972 // Note: quick and dirty storage for the 'executable' bit w/o changing | |
973 // schemas, we use the high bit of 'type' field. | |
974 record->namespace_.type = static_cast<AppCacheNamespaceType> | |
975 (type_with_executable_bit & 0x7ffffff); | |
976 record->namespace_.is_executable = | |
977 (type_with_executable_bit & 0x80000000) != 0; | |
978 DCHECK(!record->namespace_.is_executable || | |
979 CommandLine::ForCurrentProcess()->HasSwitch(kEnableExecutableHandlers)); | |
980 } | |
981 | |
982 void AppCacheDatabase::ReadOnlineWhiteListRecord( | |
983 const sql::Statement& statement, OnlineWhiteListRecord* record) { | |
984 record->cache_id = statement.ColumnInt64(0); | |
985 record->namespace_url = GURL(statement.ColumnString(1)); | |
986 record->is_pattern = statement.ColumnBool(2); | |
987 } | |
988 | |
989 bool AppCacheDatabase::LazyOpen(bool create_if_needed) { | |
990 if (db_) | |
991 return true; | |
992 | |
993 // If we tried and failed once, don't try again in the same session | |
994 // to avoid creating an incoherent mess on disk. | |
995 if (is_disabled_) | |
996 return false; | |
997 | |
998 // Avoid creating a database at all if we can. | |
999 bool use_in_memory_db = db_file_path_.empty(); | |
1000 if (!create_if_needed && | |
1001 (use_in_memory_db || !base::PathExists(db_file_path_))) { | |
1002 return false; | |
1003 } | |
1004 | |
1005 db_.reset(new sql::Connection); | |
1006 meta_table_.reset(new sql::MetaTable); | |
1007 | |
1008 db_->set_histogram_tag("AppCache"); | |
1009 | |
1010 bool opened = false; | |
1011 if (use_in_memory_db) { | |
1012 opened = db_->OpenInMemory(); | |
1013 } else if (!base::CreateDirectory(db_file_path_.DirName())) { | |
1014 LOG(ERROR) << "Failed to create appcache directory."; | |
1015 } else { | |
1016 opened = db_->Open(db_file_path_); | |
1017 if (opened) | |
1018 db_->Preload(); | |
1019 } | |
1020 | |
1021 if (!opened || !db_->QuickIntegrityCheck() || !EnsureDatabaseVersion()) { | |
1022 LOG(ERROR) << "Failed to open the appcache database."; | |
1023 AppCacheHistograms::CountInitResult( | |
1024 AppCacheHistograms::SQL_DATABASE_ERROR); | |
1025 | |
1026 // We're unable to open the database. This is a fatal error | |
1027 // which we can't recover from. We try to handle it by deleting | |
1028 // the existing appcache data and starting with a clean slate in | |
1029 // this browser session. | |
1030 if (!use_in_memory_db && DeleteExistingAndCreateNewDatabase()) | |
1031 return true; | |
1032 | |
1033 Disable(); | |
1034 return false; | |
1035 } | |
1036 | |
1037 AppCacheHistograms::CountInitResult(AppCacheHistograms::INIT_OK); | |
1038 was_corruption_detected_ = false; | |
1039 db_->set_error_callback( | |
1040 base::Bind(&AppCacheDatabase::OnDatabaseError, base::Unretained(this))); | |
1041 return true; | |
1042 } | |
1043 | |
1044 bool AppCacheDatabase::EnsureDatabaseVersion() { | |
1045 if (!sql::MetaTable::DoesTableExist(db_.get())) | |
1046 return CreateSchema(); | |
1047 | |
1048 if (!meta_table_->Init(db_.get(), kCurrentVersion, kCompatibleVersion)) | |
1049 return false; | |
1050 | |
1051 if (meta_table_->GetCompatibleVersionNumber() > kCurrentVersion) { | |
1052 LOG(WARNING) << "AppCache database is too new."; | |
1053 return false; | |
1054 } | |
1055 | |
1056 std::string stored_flags; | |
1057 meta_table_->GetValue(kExperimentFlagsKey, &stored_flags); | |
1058 if (stored_flags != GetActiveExperimentFlags()) | |
1059 return false; | |
1060 | |
1061 if (meta_table_->GetVersionNumber() < kCurrentVersion) | |
1062 return UpgradeSchema(); | |
1063 | |
1064 #ifndef NDEBUG | |
1065 DCHECK(sql::MetaTable::DoesTableExist(db_.get())); | |
1066 for (int i = 0; i < kTableCount; ++i) { | |
1067 DCHECK(db_->DoesTableExist(kTables[i].table_name)); | |
1068 } | |
1069 for (int i = 0; i < kIndexCount; ++i) { | |
1070 DCHECK(db_->DoesIndexExist(kIndexes[i].index_name)); | |
1071 } | |
1072 #endif | |
1073 | |
1074 return true; | |
1075 } | |
1076 | |
1077 bool AppCacheDatabase::CreateSchema() { | |
1078 sql::Transaction transaction(db_.get()); | |
1079 if (!transaction.Begin()) | |
1080 return false; | |
1081 | |
1082 if (!meta_table_->Init(db_.get(), kCurrentVersion, kCompatibleVersion)) | |
1083 return false; | |
1084 | |
1085 if (!meta_table_->SetValue(kExperimentFlagsKey, | |
1086 GetActiveExperimentFlags())) { | |
1087 return false; | |
1088 } | |
1089 | |
1090 for (int i = 0; i < kTableCount; ++i) { | |
1091 if (!CreateTable(db_.get(), kTables[i])) | |
1092 return false; | |
1093 } | |
1094 | |
1095 for (int i = 0; i < kIndexCount; ++i) { | |
1096 if (!CreateIndex(db_.get(), kIndexes[i])) | |
1097 return false; | |
1098 } | |
1099 | |
1100 return transaction.Commit(); | |
1101 } | |
1102 | |
1103 bool AppCacheDatabase::UpgradeSchema() { | |
1104 #if defined(APPCACHE_USE_SIMPLE_CACHE) | |
1105 return DeleteExistingAndCreateNewDatabase(); | |
1106 #else | |
1107 if (meta_table_->GetVersionNumber() == 3) { | |
1108 // version 3 was pre 12/17/2011 | |
1109 DCHECK_EQ(strcmp(kNamespacesTable, kTables[3].table_name), 0); | |
1110 DCHECK_EQ(strcmp(kNamespacesTable, kIndexes[6].table_name), 0); | |
1111 DCHECK_EQ(strcmp(kNamespacesTable, kIndexes[7].table_name), 0); | |
1112 DCHECK_EQ(strcmp(kNamespacesTable, kIndexes[8].table_name), 0); | |
1113 | |
1114 const TableInfo kNamespaceTable_v4 = { | |
1115 kNamespacesTable, | |
1116 "(cache_id INTEGER," | |
1117 " origin TEXT," // intentionally not normalized | |
1118 " type INTEGER," | |
1119 " namespace_url TEXT," | |
1120 " target_url TEXT)" | |
1121 }; | |
1122 | |
1123 // Migrate from the old FallbackNameSpaces to the newer Namespaces table, | |
1124 // but without the is_pattern column added in v5. | |
1125 sql::Transaction transaction(db_.get()); | |
1126 if (!transaction.Begin() || | |
1127 !CreateTable(db_.get(), kNamespaceTable_v4)) { | |
1128 return false; | |
1129 } | |
1130 | |
1131 // Move data from the old table to the new table, setting the | |
1132 // 'type' for all current records to the value for | |
1133 // APPCACHE_FALLBACK_NAMESPACE. | |
1134 DCHECK_EQ(0, static_cast<int>(APPCACHE_FALLBACK_NAMESPACE)); | |
1135 if (!db_->Execute( | |
1136 "INSERT INTO Namespaces" | |
1137 " SELECT cache_id, origin, 0, namespace_url, fallback_entry_url" | |
1138 " FROM FallbackNameSpaces")) { | |
1139 return false; | |
1140 } | |
1141 | |
1142 // Drop the old table, indexes on that table are also removed by this. | |
1143 if (!db_->Execute("DROP TABLE FallbackNameSpaces")) | |
1144 return false; | |
1145 | |
1146 // Create new indexes. | |
1147 if (!CreateIndex(db_.get(), kIndexes[6]) || | |
1148 !CreateIndex(db_.get(), kIndexes[7]) || | |
1149 !CreateIndex(db_.get(), kIndexes[8])) { | |
1150 return false; | |
1151 } | |
1152 | |
1153 meta_table_->SetVersionNumber(4); | |
1154 meta_table_->SetCompatibleVersionNumber(4); | |
1155 if (!transaction.Commit()) | |
1156 return false; | |
1157 } | |
1158 | |
1159 if (meta_table_->GetVersionNumber() == 4) { | |
1160 // version 4 pre 3/30/2013 | |
1161 // Add the is_pattern column to the Namespaces and OnlineWhitelists tables. | |
1162 DCHECK_EQ(strcmp(kNamespacesTable, "Namespaces"), 0); | |
1163 sql::Transaction transaction(db_.get()); | |
1164 if (!transaction.Begin()) | |
1165 return false; | |
1166 if (!db_->Execute( | |
1167 "ALTER TABLE Namespaces ADD COLUMN" | |
1168 " is_pattern INTEGER CHECK(is_pattern IN (0, 1))")) { | |
1169 return false; | |
1170 } | |
1171 if (!db_->Execute( | |
1172 "ALTER TABLE OnlineWhitelists ADD COLUMN" | |
1173 " is_pattern INTEGER CHECK(is_pattern IN (0, 1))")) { | |
1174 return false; | |
1175 } | |
1176 meta_table_->SetVersionNumber(5); | |
1177 meta_table_->SetCompatibleVersionNumber(5); | |
1178 return transaction.Commit(); | |
1179 } | |
1180 | |
1181 // If there is no upgrade path for the version on disk to the current | |
1182 // version, nuke everything and start over. | |
1183 return DeleteExistingAndCreateNewDatabase(); | |
1184 #endif | |
1185 } | |
1186 | |
1187 void AppCacheDatabase::ResetConnectionAndTables() { | |
1188 meta_table_.reset(); | |
1189 db_.reset(); | |
1190 } | |
1191 | |
1192 bool AppCacheDatabase::DeleteExistingAndCreateNewDatabase() { | |
1193 DCHECK(!db_file_path_.empty()); | |
1194 DCHECK(base::PathExists(db_file_path_)); | |
1195 VLOG(1) << "Deleting existing appcache data and starting over."; | |
1196 | |
1197 ResetConnectionAndTables(); | |
1198 | |
1199 // This also deletes the disk cache data. | |
1200 base::FilePath directory = db_file_path_.DirName(); | |
1201 if (!base::DeleteFile(directory, true)) | |
1202 return false; | |
1203 | |
1204 // Make sure the steps above actually deleted things. | |
1205 if (base::PathExists(directory)) | |
1206 return false; | |
1207 | |
1208 if (!base::CreateDirectory(directory)) | |
1209 return false; | |
1210 | |
1211 // So we can't go recursive. | |
1212 if (is_recreating_) | |
1213 return false; | |
1214 | |
1215 base::AutoReset<bool> auto_reset(&is_recreating_, true); | |
1216 return LazyOpen(true); | |
1217 } | |
1218 | |
1219 void AppCacheDatabase::OnDatabaseError(int err, sql::Statement* stmt) { | |
1220 was_corruption_detected_ |= sql::IsErrorCatastrophic(err); | |
1221 if (!db_->ShouldIgnoreSqliteError(err)) | |
1222 DLOG(ERROR) << db_->GetErrorMessage(); | |
1223 // TODO: Maybe use non-catostrophic errors to trigger a full integrity check? | |
1224 } | |
1225 | |
1226 } // namespace appcache | |
OLD | NEW |