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

Side by Side Diff: chrome/browser/sync/syncable/directory_backing_store.cc

Issue 2830027: Remove extended attributes. The lame broken codepath in the DBS was causing (Closed)
Patch Set: Synced with TOT, resolved conflicts. Created 10 years, 5 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
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 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/sync/syncable/directory_backing_store.h" 5 #include "chrome/browser/sync/syncable/directory_backing_store.h"
6 6
7 #include "build/build_config.h" 7 #include "build/build_config.h"
8 8
9 #if defined(OS_MACOSX) 9 #if defined(OS_MACOSX)
10 #include <CoreFoundation/CoreFoundation.h> 10 #include <CoreFoundation/CoreFoundation.h>
(...skipping 22 matching lines...) Expand all
33 using std::string; 33 using std::string;
34 34
35 namespace syncable { 35 namespace syncable {
36 36
37 // This just has to be big enough to hold an UPDATE or INSERT statement that 37 // This just has to be big enough to hold an UPDATE or INSERT statement that
38 // modifies all the columns in the entry table. 38 // modifies all the columns in the entry table.
39 static const string::size_type kUpdateStatementBufferSize = 2048; 39 static const string::size_type kUpdateStatementBufferSize = 2048;
40 40
41 // Increment this version whenever updating DB tables. 41 // Increment this version whenever updating DB tables.
42 extern const int32 kCurrentDBVersion; // Global visibility for our unittest. 42 extern const int32 kCurrentDBVersion; // Global visibility for our unittest.
43 const int32 kCurrentDBVersion = 71; 43 const int32 kCurrentDBVersion = 72;
44 44
45 namespace { 45 namespace {
46 46
47 int ExecQuery(sqlite3* dbhandle, const char* query) { 47 int ExecQuery(sqlite3* dbhandle, const char* query) {
48 SQLStatement statement; 48 SQLStatement statement;
49 int result = statement.prepare(dbhandle, query); 49 int result = statement.prepare(dbhandle, query);
50 if (SQLITE_OK != result) 50 if (SQLITE_OK != result)
51 return result; 51 return result;
52 do { 52 do {
53 result = statement.step(); 53 result = statement.step();
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after
208 SetFileAttributes(backing_filepath_.value().c_str(), 208 SetFileAttributes(backing_filepath_.value().c_str(),
209 attrs | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED); 209 attrs | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED);
210 #endif 210 #endif
211 211
212 return true; 212 return true;
213 } 213 }
214 return false; 214 return false;
215 } 215 }
216 216
217 DirOpenResult DirectoryBackingStore::Load(MetahandlesIndex* entry_bucket, 217 DirOpenResult DirectoryBackingStore::Load(MetahandlesIndex* entry_bucket,
218 ExtendedAttributes* xattrs_bucket,
219 Directory::KernelLoadInfo* kernel_load_info) { 218 Directory::KernelLoadInfo* kernel_load_info) {
220 if (!BeginLoad()) 219 if (!BeginLoad())
221 return FAILED_OPEN_DATABASE; 220 return FAILED_OPEN_DATABASE;
222 221
223 DirOpenResult result = InitializeTables(); 222 DirOpenResult result = InitializeTables();
224 if (OPENED != result) 223 if (OPENED != result)
225 return result; 224 return result;
226 225
227 if (!DropDeletedEntries() || 226 if (!DropDeletedEntries() ||
228 !LoadEntries(entry_bucket) || 227 !LoadEntries(entry_bucket) ||
229 !LoadExtendedAttributes(xattrs_bucket) ||
230 !LoadInfo(kernel_load_info)) { 228 !LoadInfo(kernel_load_info)) {
231 return FAILED_DATABASE_CORRUPT; 229 return FAILED_DATABASE_CORRUPT;
232 } 230 }
233 231
234 EndLoad(); 232 EndLoad();
235 return OPENED; 233 return OPENED;
236 } 234 }
237 235
238 bool DirectoryBackingStore::BeginLoad() { 236 bool DirectoryBackingStore::BeginLoad() {
239 DCHECK(load_dbhandle_ == NULL); 237 DCHECK(load_dbhandle_ == NULL);
(...skipping 14 matching lines...) Expand all
254 252
255 bool DirectoryBackingStore::SaveChanges( 253 bool DirectoryBackingStore::SaveChanges(
256 const Directory::SaveChangesSnapshot& snapshot) { 254 const Directory::SaveChangesSnapshot& snapshot) {
257 sqlite3* dbhandle = LazyGetSaveHandle(); 255 sqlite3* dbhandle = LazyGetSaveHandle();
258 256
259 // SQLTransaction::BeginExclusive causes a disk write to occur. This is not 257 // SQLTransaction::BeginExclusive causes a disk write to occur. This is not
260 // something that should happen every 10 seconds when this function runs, so 258 // something that should happen every 10 seconds when this function runs, so
261 // just stop here if there's nothing to save. 259 // just stop here if there's nothing to save.
262 bool save_info = 260 bool save_info =
263 (Directory::KERNEL_SHARE_INFO_DIRTY == snapshot.kernel_info_status); 261 (Directory::KERNEL_SHARE_INFO_DIRTY == snapshot.kernel_info_status);
264 if (snapshot.dirty_metas.size() < 1 && snapshot.dirty_xattrs.size() < 1 && 262 if (snapshot.dirty_metas.size() < 1 && !save_info)
265 !save_info)
266 return true; 263 return true;
267 264
268 SQLTransaction transaction(dbhandle); 265 SQLTransaction transaction(dbhandle);
269 if (SQLITE_OK != transaction.BeginExclusive()) 266 if (SQLITE_OK != transaction.BeginExclusive())
270 return false; 267 return false;
271 268
272 for (OriginalEntries::const_iterator i = snapshot.dirty_metas.begin(); 269 for (OriginalEntries::const_iterator i = snapshot.dirty_metas.begin();
273 i != snapshot.dirty_metas.end(); ++i) { 270 i != snapshot.dirty_metas.end(); ++i) {
274 DCHECK(i->is_dirty()); 271 DCHECK(i->is_dirty());
275 if (!SaveEntryToDB(*i)) 272 if (!SaveEntryToDB(*i))
276 return false; 273 return false;
277 } 274 }
278 275
279 for (ExtendedAttributes::const_iterator i = snapshot.dirty_xattrs.begin();
280 i != snapshot.dirty_xattrs.end(); ++i) {
281 DCHECK(i->second.dirty);
282 if (i->second.is_deleted) {
283 if (!DeleteExtendedAttributeFromDB(i))
284 return false;
285 } else {
286 if (!SaveExtendedAttributeToDB(i))
287 return false;
288 }
289 }
290
291 if (save_info) { 276 if (save_info) {
292 const Directory::PersistedKernelInfo& info = snapshot.kernel_info; 277 const Directory::PersistedKernelInfo& info = snapshot.kernel_info;
293 SQLStatement update; 278 SQLStatement update;
294 update.prepare(dbhandle, "UPDATE share_info " 279 update.prepare(dbhandle, "UPDATE share_info "
295 "SET store_birthday = ?, " 280 "SET store_birthday = ?, "
296 "next_id = ?"); 281 "next_id = ?");
297 update.bind_string(0, info.store_birthday); 282 update.bind_string(0, info.store_birthday);
298 update.bind_int64(1, info.next_id); 283 update.bind_int64(1, info.next_id);
299 284
300 if (!(SQLITE_DONE == update.step() && 285 if (!(SQLITE_DONE == update.step() &&
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
348 if (MigrateVersion69To70()) 333 if (MigrateVersion69To70())
349 version_on_disk = 70; 334 version_on_disk = 70;
350 } 335 }
351 336
352 // Version 71 changed the sync progress information to be per-datatype. 337 // Version 71 changed the sync progress information to be per-datatype.
353 if (version_on_disk == 70) { 338 if (version_on_disk == 70) {
354 if (MigrateVersion70To71()) 339 if (MigrateVersion70To71())
355 version_on_disk = 71; 340 version_on_disk = 71;
356 } 341 }
357 342
343 // Version 72 removed extended attributes, a legacy way to do extensible
344 // key/value information, stored in their own table.
345 if (version_on_disk == 71) {
346 if (MigrateVersion71To72())
347 version_on_disk = 72;
348 }
349
358 // If one of the migrations requested it, drop columns that aren't current. 350 // If one of the migrations requested it, drop columns that aren't current.
359 // It's only safe to do this after migrating all the way to the current 351 // It's only safe to do this after migrating all the way to the current
360 // version. 352 // version.
361 if (version_on_disk == kCurrentDBVersion && needs_column_refresh_) { 353 if (version_on_disk == kCurrentDBVersion && needs_column_refresh_) {
362 if (!RefreshColumns()) 354 if (!RefreshColumns())
363 version_on_disk = 0; 355 version_on_disk = 0;
364 } 356 }
365 357
366 // A final, alternative catch-all migration to simply re-sync everything. 358 // A final, alternative catch-all migration to simply re-sync everything.
367 if (version_on_disk != kCurrentDBVersion) { 359 if (version_on_disk != kCurrentDBVersion) {
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
443 base::hash_set<int64> handles; 435 base::hash_set<int64> handles;
444 EntryKernel* kernel = NULL; 436 EntryKernel* kernel = NULL;
445 int query_result; 437 int query_result;
446 while (SQLITE_ROW == (query_result = UnpackEntry(&statement, &kernel))) { 438 while (SQLITE_ROW == (query_result = UnpackEntry(&statement, &kernel))) {
447 DCHECK(handles.insert(kernel->ref(META_HANDLE)).second); // Only in debug. 439 DCHECK(handles.insert(kernel->ref(META_HANDLE)).second); // Only in debug.
448 entry_bucket->insert(kernel); 440 entry_bucket->insert(kernel);
449 } 441 }
450 return SQLITE_DONE == query_result; 442 return SQLITE_DONE == query_result;
451 } 443 }
452 444
453 bool DirectoryBackingStore::LoadExtendedAttributes(
454 ExtendedAttributes* xattrs_bucket) {
455 SQLStatement statement;
456 statement.prepare(
457 load_dbhandle_,
458 "SELECT metahandle, key, value FROM extended_attributes");
459 int step_result = statement.step();
460 while (SQLITE_ROW == step_result) {
461 int64 metahandle = statement.column_int64(0);
462
463 string path_string_key;
464 statement.column_string(1, &path_string_key);
465
466 ExtendedAttributeValue val;
467 statement.column_blob_as_vector(2, &(val.value));
468 val.is_deleted = false;
469
470 ExtendedAttributeKey key(metahandle, path_string_key);
471 xattrs_bucket->insert(std::make_pair(key, val));
472 step_result = statement.step();
473 }
474
475 return SQLITE_DONE == step_result;
476 }
477
478 bool DirectoryBackingStore::LoadInfo(Directory::KernelLoadInfo* info) { 445 bool DirectoryBackingStore::LoadInfo(Directory::KernelLoadInfo* info) {
479 { 446 {
480 SQLStatement query; 447 SQLStatement query;
481 query.prepare(load_dbhandle_, 448 query.prepare(load_dbhandle_,
482 "SELECT store_birthday, next_id, cache_guid " 449 "SELECT store_birthday, next_id, cache_guid "
483 "FROM share_info"); 450 "FROM share_info");
484 if (SQLITE_ROW != query.step()) 451 if (SQLITE_ROW != query.step())
485 return false; 452 return false;
486 info->kernel_info.store_birthday = query.column_string(0); 453 info->kernel_info.store_birthday = query.column_string(0);
487 info->kernel_info.next_id = query.column_int64(1); 454 info->kernel_info.next_id = query.column_int64(1);
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
535 values.append(" )"); 502 values.append(" )");
536 query.append(values); 503 query.append(values);
537 SQLStatement statement; 504 SQLStatement statement;
538 statement.prepare(save_dbhandle_, query.c_str()); 505 statement.prepare(save_dbhandle_, query.c_str());
539 BindFields(entry, &statement); 506 BindFields(entry, &statement);
540 return (SQLITE_DONE == statement.step() && 507 return (SQLITE_DONE == statement.step() &&
541 SQLITE_OK == statement.reset() && 508 SQLITE_OK == statement.reset() &&
542 1 == statement.changes()); 509 1 == statement.changes());
543 } 510 }
544 511
545 bool DirectoryBackingStore::SaveExtendedAttributeToDB(
546 ExtendedAttributes::const_iterator i) {
547 DCHECK(save_dbhandle_);
548 SQLStatement insert;
549 insert.prepare(save_dbhandle_,
550 "INSERT INTO extended_attributes "
551 "(metahandle, key, value) "
552 "values ( ?, ?, ? )");
553 insert.bind_int64(0, i->first.metahandle);
554 insert.bind_string(1, i->first.key);
555 insert.bind_blob(2, &i->second.value.at(0), i->second.value.size());
556 return (SQLITE_DONE == insert.step() &&
557 SQLITE_OK == insert.reset() &&
558 1 == insert.changes());
559 }
560
561 bool DirectoryBackingStore::DeleteExtendedAttributeFromDB(
562 ExtendedAttributes::const_iterator i) {
563 DCHECK(save_dbhandle_);
564 SQLStatement delete_attribute;
565 delete_attribute.prepare(save_dbhandle_,
566 "DELETE FROM extended_attributes "
567 "WHERE metahandle = ? AND key = ? ");
568 delete_attribute.bind_int64(0, i->first.metahandle);
569 delete_attribute.bind_string(1, i->first.key);
570 if (!(SQLITE_DONE == delete_attribute.step() &&
571 SQLITE_OK == delete_attribute.reset() &&
572 1 == delete_attribute.changes())) {
573 LOG(ERROR) << "DeleteExtendedAttributeFromDB(),StepDone() failed "
574 << "for metahandle: " << i->first.metahandle << " key: "
575 << i->first.key;
576 return false;
577 }
578 // The attribute may have never been saved to the database if it was
579 // created and then immediately deleted. So don't check that we
580 // deleted exactly 1 row.
581 return true;
582 }
583
584 bool DirectoryBackingStore::DropDeletedEntries() { 512 bool DirectoryBackingStore::DropDeletedEntries() {
585 static const char delete_extended_attributes[] =
586 "DELETE FROM extended_attributes WHERE metahandle IN "
587 "(SELECT metahandle from death_row)";
588 static const char delete_metas[] = "DELETE FROM metas WHERE metahandle IN " 513 static const char delete_metas[] = "DELETE FROM metas WHERE metahandle IN "
589 "(SELECT metahandle from death_row)"; 514 "(SELECT metahandle from death_row)";
590 // Put all statements into a transaction for better performance 515 // Put all statements into a transaction for better performance
591 SQLTransaction transaction(load_dbhandle_); 516 SQLTransaction transaction(load_dbhandle_);
592 transaction.Begin(); 517 transaction.Begin();
593 if (SQLITE_DONE != ExecQuery( 518 if (SQLITE_DONE != ExecQuery(
594 load_dbhandle_, 519 load_dbhandle_,
595 "CREATE TEMP TABLE death_row (metahandle BIGINT)")) { 520 "CREATE TEMP TABLE death_row (metahandle BIGINT)")) {
596 return false; 521 return false;
597 } 522 }
598 if (SQLITE_DONE != ExecQuery(load_dbhandle_, 523 if (SQLITE_DONE != ExecQuery(load_dbhandle_,
599 "INSERT INTO death_row " 524 "INSERT INTO death_row "
600 "SELECT metahandle from metas WHERE is_del > 0 " 525 "SELECT metahandle from metas WHERE is_del > 0 "
601 " AND is_unsynced < 1" 526 " AND is_unsynced < 1"
602 " AND is_unapplied_update < 1")) { 527 " AND is_unapplied_update < 1")) {
603 return false; 528 return false;
604 } 529 }
605 if (SQLITE_DONE != ExecQuery(load_dbhandle_, delete_extended_attributes)) {
606 return false;
607 }
608 if (SQLITE_DONE != ExecQuery(load_dbhandle_, delete_metas)) { 530 if (SQLITE_DONE != ExecQuery(load_dbhandle_, delete_metas)) {
609 return false; 531 return false;
610 } 532 }
611 if (SQLITE_DONE != ExecQuery(load_dbhandle_, "DROP TABLE death_row")) { 533 if (SQLITE_DONE != ExecQuery(load_dbhandle_, "DROP TABLE death_row")) {
612 return false; 534 return false;
613 } 535 }
614 transaction.Commit(); 536 transaction.Commit();
615 return true; 537 return true;
616 } 538 }
617 539
618 int DirectoryBackingStore::SafeDropTable(const char* table_name) { 540 int DirectoryBackingStore::SafeDropTable(const char* table_name) {
619 string query = "DROP TABLE IF EXISTS "; 541 string query = "DROP TABLE IF EXISTS ";
620 query.append(table_name); 542 query.append(table_name);
621 SQLStatement statement; 543 SQLStatement statement;
622 int result = statement.prepare(load_dbhandle_, query.data(), 544 int result = statement.prepare(load_dbhandle_, query.data(),
623 query.size()); 545 query.size());
624 if (SQLITE_OK == result) { 546 if (SQLITE_OK == result) {
625 result = statement.step(); 547 result = statement.step();
626 if (SQLITE_DONE == result) 548 if (SQLITE_DONE == result)
627 statement.finalize(); 549 statement.finalize();
628 } 550 }
629 551
630 return result; 552 return result;
631 } 553 }
632 554
633 int DirectoryBackingStore::CreateExtendedAttributeTable() {
634 int result = SafeDropTable("extended_attributes");
635 if (result != SQLITE_DONE)
636 return result;
637 LOG(INFO) << "CreateExtendedAttributeTable";
638 return ExecQuery(load_dbhandle_,
639 "CREATE TABLE extended_attributes("
640 "metahandle bigint, "
641 "key varchar(127), "
642 "value blob, "
643 "PRIMARY KEY(metahandle, key) ON CONFLICT REPLACE)");
644 }
645
646 void DirectoryBackingStore::DropAllTables() { 555 void DirectoryBackingStore::DropAllTables() {
647 SafeDropTable("metas"); 556 SafeDropTable("metas");
648 SafeDropTable("temp_metas"); 557 SafeDropTable("temp_metas");
649 SafeDropTable("share_info"); 558 SafeDropTable("share_info");
650 SafeDropTable("temp_share_info"); 559 SafeDropTable("temp_share_info");
651 SafeDropTable("share_version"); 560 SafeDropTable("share_version");
652 SafeDropTable("extended_attributes"); 561 SafeDropTable("extended_attributes");
653 SafeDropTable("models"); 562 SafeDropTable("models");
654 needs_column_refresh_ = false; 563 needs_column_refresh_ = false;
655 } 564 }
(...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after
882 return false; 791 return false;
883 SafeDropTable("share_info"); 792 SafeDropTable("share_info");
884 result = ExecQuery(load_dbhandle_, 793 result = ExecQuery(load_dbhandle_,
885 "ALTER TABLE temp_share_info RENAME TO share_info"); 794 "ALTER TABLE temp_share_info RENAME TO share_info");
886 if (result != SQLITE_DONE) 795 if (result != SQLITE_DONE)
887 return false; 796 return false;
888 SetVersion(71); 797 SetVersion(71);
889 return true; 798 return true;
890 } 799 }
891 800
801 bool DirectoryBackingStore::MigrateVersion71To72() {
802 SafeDropTable("extended_attributes");
803 SetVersion(72);
804 return true;
805 }
806
892 int DirectoryBackingStore::CreateTables() { 807 int DirectoryBackingStore::CreateTables() {
893 LOG(INFO) << "First run, creating tables"; 808 LOG(INFO) << "First run, creating tables";
894 // Create two little tables share_version and share_info 809 // Create two little tables share_version and share_info
895 int result = ExecQuery(load_dbhandle_, 810 int result = ExecQuery(load_dbhandle_,
896 "CREATE TABLE share_version (" 811 "CREATE TABLE share_version ("
897 "id VARCHAR(128) primary key, data INT)"); 812 "id VARCHAR(128) primary key, data INT)");
898 if (result != SQLITE_DONE) 813 if (result != SQLITE_DONE)
899 return result; 814 return result;
900 { 815 {
901 SQLStatement statement; 816 SQLStatement statement;
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
943 const int64 now = Now(); 858 const int64 now = Now();
944 SQLStatement statement; 859 SQLStatement statement;
945 statement.prepare(load_dbhandle_, 860 statement.prepare(load_dbhandle_,
946 "INSERT INTO metas " 861 "INSERT INTO metas "
947 "( id, metahandle, is_dir, ctime, mtime) " 862 "( id, metahandle, is_dir, ctime, mtime) "
948 "VALUES ( \"r\", 1, 1, ?, ?)"); 863 "VALUES ( \"r\", 1, 1, ?, ?)");
949 statement.bind_int64(0, now); 864 statement.bind_int64(0, now);
950 statement.bind_int64(1, now); 865 statement.bind_int64(1, now);
951 result = statement.step(); 866 result = statement.step();
952 } 867 }
953 if (result != SQLITE_DONE)
954 return result;
955 result = CreateExtendedAttributeTable();
956 return result; 868 return result;
957 } 869 }
958 870
959 sqlite3* DirectoryBackingStore::LazyGetSaveHandle() { 871 sqlite3* DirectoryBackingStore::LazyGetSaveHandle() {
960 if (!save_dbhandle_ && !OpenAndConfigureHandleHelper(&save_dbhandle_)) { 872 if (!save_dbhandle_ && !OpenAndConfigureHandleHelper(&save_dbhandle_)) {
961 DCHECK(FALSE) << "Unable to open handle for saving"; 873 DCHECK(FALSE) << "Unable to open handle for saving";
962 return NULL; 874 return NULL;
963 } 875 }
964 return save_dbhandle_; 876 return save_dbhandle_;
965 } 877 }
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
998 "name TEXT, " 910 "name TEXT, "
999 "store_birthday TEXT, " 911 "store_birthday TEXT, "
1000 "db_create_version TEXT, " 912 "db_create_version TEXT, "
1001 "db_create_time INT, " 913 "db_create_time INT, "
1002 "next_id INT default -2, " 914 "next_id INT default -2, "
1003 "cache_guid TEXT)"); 915 "cache_guid TEXT)");
1004 return ExecQuery(load_dbhandle_, query.c_str()); 916 return ExecQuery(load_dbhandle_, query.c_str());
1005 } 917 }
1006 918
1007 } // namespace syncable 919 } // namespace syncable
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698