1 // Copyright 2013 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 "chrome/browser/sync_file_system/drive_backend_v1/drive_metadata_store.h" 6 7 #include <utility> 8 #include <vector> 9 10 #include "base/bind.h" 11 #include "base/callback.h" 12 #include "base/files/file_path.h" 13 #include "base/location.h" 14 #include "base/message_loop/message_loop_proxy.h" 15 #include "base/sequenced_task_runner.h" 16 #include "base/stl_util.h" 17 #include "base/strings/string_number_conversions.h" 18 #include "base/strings/string_util.h" 19 #include "base/strings/stringprintf.h" 20 #include "base/task_runner_util.h" 21 #include "base/values.h" 22 #include "chrome/browser/sync_file_system/drive_backend/metadata_db_migration_util.h" 23 #include "chrome/browser/sync_file_system/drive_backend_v1/drive_file_sync_service.h" 24 #include "chrome/browser/sync_file_system/drive_backend_v1/drive_file_sync_util.h" 25 #include "chrome/browser/sync_file_system/logger.h" 26 #include "chrome/browser/sync_file_system/sync_file_system.pb.h" 27 #include "chrome/browser/sync_file_system/syncable_file_system_util.h" 28 #include "third_party/leveldatabase/src/include/leveldb/db.h" 29 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h" 30 #include "url/gurl.h" 31 #include "webkit/browser/fileapi/file_system_url.h" 32 #include "webkit/common/fileapi/file_system_util.h" 33 34 using fileapi::FileSystemURL; 35 36 namespace sync_file_system { 37 38 typedef DriveMetadataStore::MetadataMap MetadataMap; 39 typedef DriveMetadataStore::OriginByResourceId OriginByResourceId; 40 typedef DriveMetadataStore::PathToMetadata PathToMetadata; 41 typedef DriveMetadataStore::ResourceIdByOrigin ResourceIdByOrigin; 42 43 const base::FilePath::CharType DriveMetadataStore::kDatabaseName[] = 44 FILE_PATH_LITERAL("DriveMetadata"); 45 46 struct DBContents { 47 SyncStatusCode status; 48 scoped_ptr<leveldb::DB> db; 49 bool created; 50 51 int64 largest_changestamp; 52 DriveMetadataStore::MetadataMap metadata_map; 53 std::string sync_root_directory_resource_id; 54 ResourceIdByOrigin incremental_sync_origins; 55 ResourceIdByOrigin disabled_origins; 56 57 DBContents() 58 : status(SYNC_STATUS_UNKNOWN), 59 created(false), 60 largest_changestamp(0) { 61 } 62 }; 63 64 namespace { 65 66 const char kDatabaseVersionKey[] = "VERSION"; 67 const int64 kCurrentDatabaseVersion = 2; 68 const char kChangeStampKey[] = "CHANGE_STAMP"; 69 const char kSyncRootDirectoryKey[] = "SYNC_ROOT_DIR"; 70 const char kDriveMetadataKeyPrefix[] = "METADATA: "; 71 const char kMetadataKeySeparator = ' '; 72 const char kDriveIncrementalSyncOriginKeyPrefix[] = "ISYNC_ORIGIN: "; 73 const char kDriveDisabledOriginKeyPrefix[] = "DISABLED_ORIGIN: "; 74 75 enum OriginSyncType { 76 INCREMENTAL_SYNC_ORIGIN, 77 DISABLED_ORIGIN 78 }; 79 80 std::string RemovePrefix(const std::string& str, const std::string& prefix) { 81 if (StartsWithASCII(str, prefix, true)) 82 return str.substr(prefix.size()); 83 return str; 84 } 85 86 std::string OriginAndPathToMetadataKey(const GURL& origin, 87 const base::FilePath& path) { 88 return kDriveMetadataKeyPrefix + origin.spec() + 89 kMetadataKeySeparator + path.AsUTF8Unsafe(); 90 } 91 92 std::string FileSystemURLToMetadataKey(const FileSystemURL& url) { 93 return OriginAndPathToMetadataKey(url.origin(), url.path()); 94 } 95 96 void MetadataKeyToOriginAndPath(const std::string& metadata_key, 97 GURL* origin, 98 base::FilePath* path) { 99 std::string key_body(RemovePrefix(metadata_key, kDriveMetadataKeyPrefix)); 100 size_t separator_position = key_body.find(kMetadataKeySeparator); 101 *origin = GURL(key_body.substr(0, separator_position)); 102 *path = base::FilePath::FromUTF8Unsafe( 103 key_body.substr(separator_position + 1)); 104 } 105 106 bool UpdateResourceIdMap(ResourceIdByOrigin* map, 107 OriginByResourceId* reverse_map, 108 const GURL& origin, 109 const std::string& resource_id) { 110 ResourceIdByOrigin::iterator found = map->find(origin); 111 if (found == map->end()) 112 return false; 113 reverse_map->erase(found->second); 114 reverse_map->insert(std::make_pair(resource_id, origin)); 115 116 found->second = resource_id; 117 return true; 118 } 119 120 //////////////////////////////////////////////////////////////////////////////// 121 122 bool IsDBEmpty(leveldb::DB* db) { 123 DCHECK(db); 124 scoped_ptr<leveldb::Iterator> itr(db->NewIterator(leveldb::ReadOptions())); 125 itr->SeekToFirst(); 126 return !itr->Valid(); 127 } 128 129 scoped_ptr<leveldb::DB> OpenDatabase(const base::FilePath& path, 130 SyncStatusCode* status, 131 bool* created) { 132 DCHECK(status); 133 DCHECK(created); 134 135 leveldb::Options options; 136 options.max_open_files = 0; // Use minimum. 137 options.create_if_missing = true; 138 leveldb::DB* db = NULL; 139 leveldb::Status db_status = leveldb::DB::Open( 140 options, path.AsUTF8Unsafe(), &db); 141 if (db_status.ok()) { 142 *created = IsDBEmpty(db); 143 } else { 144 delete db; 145 db = NULL; 146 } 147 *status = LevelDBStatusToSyncStatusCode(db_status); 148 149 return make_scoped_ptr(db); 150 } 151 152 SyncStatusCode WriteInitialData(leveldb::DB* db) { 153 DCHECK(db); 154 return LevelDBStatusToSyncStatusCode(db->Put( 155 leveldb::WriteOptions(), 156 kDatabaseVersionKey, 157 base::Int64ToString(kCurrentDatabaseVersion))); 158 } 159 160 SyncStatusCode MigrateDatabaseIfNeeded(leveldb::DB* db) { 161 DCHECK(db); 162 std::string value; 163 leveldb::Status status = db->Get(leveldb::ReadOptions(), 164 kDatabaseVersionKey, &value); 165 int64 version = 0; 166 if (status.ok()) { 167 if (!base::StringToInt64(value, &version)) 168 return SYNC_DATABASE_ERROR_FAILED; 169 } else { 170 if (!status.IsNotFound()) 171 return SYNC_DATABASE_ERROR_FAILED; 172 } 173 174 switch (version) { 175 case 0: 176 drive_backend::MigrateDatabaseFromV0ToV1(db); 177 // fall-through 178 case 1: 179 drive_backend::MigrateDatabaseFromV1ToV2(db); 180 // fall-through 181 case 2: 182 DCHECK_EQ(2, kCurrentDatabaseVersion); 183 return SYNC_STATUS_OK; 184 default: 185 return SYNC_DATABASE_ERROR_FAILED; 186 } 187 } 188 189 SyncStatusCode ReadContents(DBContents* contents) { 190 DCHECK(contents); 191 DCHECK(contents->db); 192 193 contents->largest_changestamp = 0; 194 contents->metadata_map.clear(); 195 contents->incremental_sync_origins.clear(); 196 197 scoped_ptr<leveldb::Iterator> itr( 198 contents->db->NewIterator(leveldb::ReadOptions())); 199 for (itr->SeekToFirst(); itr->Valid(); itr->Next()) { 200 std::string key = itr->key().ToString(); 201 if (key == kChangeStampKey) { 202 bool success = base::StringToInt64(itr->value().ToString(), 203 &contents->largest_changestamp); 204 DCHECK(success); 205 continue; 206 } 207 208 if (key == kSyncRootDirectoryKey) { 209 std::string resource_id = itr->value().ToString(); 210 if (IsDriveAPIDisabled()) 211 resource_id = drive_backend::AddWapiFolderPrefix(resource_id); 212 contents->sync_root_directory_resource_id = resource_id; 213 continue; 214 } 215 216 if (StartsWithASCII(key, kDriveMetadataKeyPrefix, true)) { 217 GURL origin; 218 base::FilePath path; 219 MetadataKeyToOriginAndPath(key, &origin, &path); 220 221 DriveMetadata metadata; 222 bool success = metadata.ParseFromString(itr->value().ToString()); 223 DCHECK(success); 224 225 if (IsDriveAPIDisabled()) { 226 metadata.set_resource_id(drive_backend::AddWapiIdPrefix( 227 metadata.resource_id(), metadata.type())); 228 } 229 230 success = contents->metadata_map[origin].insert( 231 std::make_pair(path, metadata)).second; 232 DCHECK(success); 233 continue; 234 } 235 236 if (StartsWithASCII(key, kDriveIncrementalSyncOriginKeyPrefix, true)) { 237 GURL origin(RemovePrefix(key, kDriveIncrementalSyncOriginKeyPrefix)); 238 DCHECK(origin.is_valid()); 239 240 std::string origin_resource_id = IsDriveAPIDisabled() 241 ? drive_backend::AddWapiFolderPrefix(itr->value().ToString()) 242 : itr->value().ToString(); 243 244 DCHECK(!ContainsKey(contents->incremental_sync_origins, origin)); 245 contents->incremental_sync_origins[origin] = origin_resource_id; 246 continue; 247 } 248 249 if (StartsWithASCII(key, kDriveDisabledOriginKeyPrefix, true)) { 250 GURL origin(RemovePrefix(key, kDriveDisabledOriginKeyPrefix)); 251 DCHECK(origin.is_valid()); 252 253 std::string origin_resource_id = IsDriveAPIDisabled() 254 ? drive_backend::AddWapiFolderPrefix(itr->value().ToString()) 255 : itr->value().ToString(); 256 257 DCHECK(!ContainsKey(contents->disabled_origins, origin)); 258 contents->disabled_origins[origin] = origin_resource_id; 259 continue; 260 } 261 } 262 263 return SYNC_STATUS_OK; 264 } 265 266 scoped_ptr<DBContents> LoadDBContents(const base::FilePath& db_path) { 267 scoped_ptr<DBContents> contents(new DBContents); 268 contents->db = OpenDatabase(db_path, 269 &contents->status, 270 &contents->created); 271 if (contents->status != SYNC_STATUS_OK) 272 return contents.Pass(); 273 274 if (contents->created) { 275 contents->status = WriteInitialData(contents->db.get()); 276 if (contents->status != SYNC_STATUS_OK) 277 return contents.Pass(); 278 } else { 279 contents->status = MigrateDatabaseIfNeeded(contents->db.get()); 280 if (contents->status != SYNC_STATUS_OK) 281 return contents.Pass(); 282 } 283 284 contents->status = ReadContents(contents.get()); 285 return contents.Pass(); 286 } 287 288 //////////////////////////////////////////////////////////////////////////////// 289 290 // Returns a key string for the given origin. 291 // For example, when |origin| is "http://www.example.com" and |sync_type| is 292 // BATCH_SYNC_ORIGIN, returns "BSYNC_ORIGIN: http://www.example.com". 293 std::string CreateKeyForOriginRoot(const GURL& origin, 294 OriginSyncType sync_type) { 295 DCHECK(origin.is_valid()); 296 switch (sync_type) { 297 case INCREMENTAL_SYNC_ORIGIN: 298 return kDriveIncrementalSyncOriginKeyPrefix + origin.spec(); 299 case DISABLED_ORIGIN: 300 return kDriveDisabledOriginKeyPrefix + origin.spec(); 301 } 302 NOTREACHED(); 303 return std::string(); 304 } 305 306 void AddOriginsToVector(std::vector<GURL>* all_origins, 307 const ResourceIdByOrigin& resource_map) { 308 for (ResourceIdByOrigin::const_iterator itr = resource_map.begin(); 309 itr != resource_map.end(); 310 ++itr) { 311 all_origins->push_back(itr->first); 312 } 313 } 314 315 void InsertReverseMap(const ResourceIdByOrigin& forward_map, 316 OriginByResourceId* backward_map) { 317 for (ResourceIdByOrigin::const_iterator itr = forward_map.begin(); 318 itr != forward_map.end(); ++itr) 319 backward_map->insert(std::make_pair(itr->second, itr->first)); 320 } 321 322 bool EraseIfExists(ResourceIdByOrigin* map, 323 const GURL& origin, 324 std::string* resource_id) { 325 ResourceIdByOrigin::iterator found = map->find(origin); 326 if (found == map->end()) 327 return false; 328 *resource_id = found->second; 329 map->erase(found); 330 return true; 331 } 332 333 void AppendMetadataDeletionToBatch(const MetadataMap& metadata_map, 334 const GURL& origin, 335 leveldb::WriteBatch* batch) { 336 MetadataMap::const_iterator found = metadata_map.find(origin); 337 if (found == metadata_map.end()) 338 return; 339 340 for (PathToMetadata::const_iterator itr = found->second.begin(); 341 itr != found->second.end(); ++itr) 342 batch->Delete(OriginAndPathToMetadataKey(origin, itr->first)); 343 } 344 345 std::string DriveTypeToString(DriveMetadata_ResourceType drive_type) { 346 switch (drive_type) { 347 case DriveMetadata_ResourceType_RESOURCE_TYPE_FILE: 348 return "file"; 349 case DriveMetadata_ResourceType_RESOURCE_TYPE_FOLDER: 350 return "folder"; 351 } 352 353 NOTREACHED(); 354 return "unknown"; 355 } 356 357 } // namespace 358 359 DriveMetadataStore::DriveMetadataStore( 360 const base::FilePath& base_dir, 361 base::SequencedTaskRunner* file_task_runner) 362 : file_task_runner_(file_task_runner), 363 base_dir_(base_dir), 364 db_status_(SYNC_STATUS_UNKNOWN), 365 largest_changestamp_(0) { 366 DCHECK(file_task_runner); 367 } 368 369 DriveMetadataStore::~DriveMetadataStore() { 370 DCHECK(CalledOnValidThread()); 371 file_task_runner_->DeleteSoon(FROM_HERE, db_.release()); 372 } 373 374 void DriveMetadataStore::Initialize(const InitializationCallback& callback) { 375 DCHECK(CalledOnValidThread()); 376 base::PostTaskAndReplyWithResult( 377 file_task_runner_.get(), FROM_HERE, 378 base::Bind(&LoadDBContents, base_dir_.Append(kDatabaseName)), 379 base::Bind(&DriveMetadataStore::DidInitialize, AsWeakPtr(), callback)); 380 } 381 382 void DriveMetadataStore::DidInitialize(const InitializationCallback& callback, 383 scoped_ptr<DBContents> contents) { 384 DCHECK(CalledOnValidThread()); 385 DCHECK(contents); 386 387 db_status_ = contents->status; 388 if (db_status_ != SYNC_STATUS_OK) { 389 callback.Run(db_status_, false); 390 file_task_runner_->DeleteSoon(FROM_HERE, contents.release()); 391 return; 392 } 393 394 db_ = contents->db.Pass(); 395 largest_changestamp_ = contents->largest_changestamp; 396 metadata_map_.swap(contents->metadata_map); 397 sync_root_directory_resource_id_ = contents->sync_root_directory_resource_id; 398 incremental_sync_origins_.swap(contents->incremental_sync_origins); 399 disabled_origins_.swap(contents->disabled_origins); 400 401 origin_by_resource_id_.clear(); 402 InsertReverseMap(incremental_sync_origins_, &origin_by_resource_id_); 403 InsertReverseMap(disabled_origins_, &origin_by_resource_id_); 404 405 callback.Run(db_status_, contents->created); 406 } 407 408 void DriveMetadataStore::SetLargestChangeStamp( 409 int64 largest_changestamp, 410 const SyncStatusCallback& callback) { 411 DCHECK(CalledOnValidThread()); 412 DCHECK_EQ(SYNC_STATUS_OK, db_status_); 413 largest_changestamp_ = largest_changestamp; 414 415 scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch); 416 batch->Put(kChangeStampKey, base::Int64ToString(largest_changestamp)); 417 return WriteToDB(batch.Pass(), callback); 418 } 419 420 int64 DriveMetadataStore::GetLargestChangeStamp() const { 421 DCHECK(CalledOnValidThread()); 422 DCHECK_EQ(SYNC_STATUS_OK, db_status_); 423 return largest_changestamp_; 424 } 425 426 void DriveMetadataStore::UpdateEntry( 427 const FileSystemURL& url, 428 const DriveMetadata& metadata, 429 const SyncStatusCallback& callback) { 430 DCHECK(CalledOnValidThread()); 431 DCHECK_EQ(SYNC_STATUS_OK, db_status_); 432 DCHECK(!metadata.conflicted() || !metadata.to_be_fetched()); 433 434 std::pair<PathToMetadata::iterator, bool> result = 435 metadata_map_[url.origin()].insert(std::make_pair(url.path(), metadata)); 436 if (!result.second) 437 result.first->second = metadata; 438 439 std::string value; 440 if (IsDriveAPIDisabled()) { 441 DriveMetadata metadata_in_db(metadata); 442 metadata_in_db.set_resource_id( 443 drive_backend::RemoveWapiIdPrefix(metadata.resource_id())); 444 bool success = metadata_in_db.SerializeToString(&value); 445 DCHECK(success); 446 } else { 447 bool success = metadata.SerializeToString(&value); 448 DCHECK(success); 449 } 450 451 scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch); 452 batch->Put(FileSystemURLToMetadataKey(url), value); 453 WriteToDB(batch.Pass(), callback); 454 } 455 456 void DriveMetadataStore::DeleteEntry( 457 const FileSystemURL& url, 458 const SyncStatusCallback& callback) { 459 DCHECK(CalledOnValidThread()); 460 MetadataMap::iterator found = metadata_map_.find(url.origin()); 461 if (found == metadata_map_.end()) { 462 RunSoon(FROM_HERE, base::Bind(callback, SYNC_DATABASE_ERROR_NOT_FOUND)); 463 return; 464 } 465 466 if (found->second.erase(url.path()) == 1) { 467 scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch); 468 batch->Delete(FileSystemURLToMetadataKey(url)); 469 WriteToDB(batch.Pass(), callback); 470 return; 471 } 472 473 RunSoon(FROM_HERE, base::Bind(callback, SYNC_DATABASE_ERROR_NOT_FOUND)); 474 } 475 476 SyncStatusCode DriveMetadataStore::ReadEntry(const FileSystemURL& url, 477 DriveMetadata* metadata) const { 478 DCHECK(CalledOnValidThread()); 479 DCHECK(metadata); 480 481 MetadataMap::const_iterator found_origin = metadata_map_.find(url.origin()); 482 if (found_origin == metadata_map_.end()) 483 return SYNC_DATABASE_ERROR_NOT_FOUND; 484 485 PathToMetadata::const_iterator found = found_origin->second.find(url.path()); 486 if (found == found_origin->second.end()) 487 return SYNC_DATABASE_ERROR_NOT_FOUND; 488 489 *metadata = found->second; 490 return SYNC_STATUS_OK; 491 } 492 493 void DriveMetadataStore::AddIncrementalSyncOrigin( 494 const GURL& origin, 495 const std::string& resource_id) { 496 DCHECK(CalledOnValidThread()); 497 DCHECK(!IsIncrementalSyncOrigin(origin)); 498 DCHECK(!IsOriginDisabled(origin)); 499 DCHECK_EQ(SYNC_STATUS_OK, db_status_); 500 501 incremental_sync_origins_.insert(std::make_pair(origin, resource_id)); 502 origin_by_resource_id_.insert(std::make_pair(resource_id, origin)); 503 504 scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch); 505 batch->Delete(CreateKeyForOriginRoot(origin, DISABLED_ORIGIN)); 506 batch->Put(CreateKeyForOriginRoot(origin, INCREMENTAL_SYNC_ORIGIN), 507 drive_backend::RemoveWapiIdPrefix(resource_id)); 508 WriteToDB(batch.Pass(), 509 base::Bind(&DriveMetadataStore::UpdateDBStatus, AsWeakPtr())); 510 } 511 512 void DriveMetadataStore::SetSyncRootDirectory(const std::string& resource_id) { 513 DCHECK(CalledOnValidThread()); 514 515 sync_root_directory_resource_id_ = resource_id; 516 517 scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch); 518 batch->Put(kSyncRootDirectoryKey, 519 drive_backend::RemoveWapiIdPrefix(resource_id)); 520 return WriteToDB(batch.Pass(), 521 base::Bind(&DriveMetadataStore::UpdateDBStatus, 522 AsWeakPtr())); 523 } 524 525 void DriveMetadataStore::SetOriginRootDirectory( 526 const GURL& origin, 527 const std::string& resource_id) { 528 DCHECK(CalledOnValidThread()); 529 DCHECK(IsKnownOrigin(origin)); 530 531 OriginSyncType sync_type; 532 if (UpdateResourceIdMap( 533 &incremental_sync_origins_, &origin_by_resource_id_, 534 origin, resource_id)) { 535 sync_type = INCREMENTAL_SYNC_ORIGIN; 536 } else if (UpdateResourceIdMap(&disabled_origins_, &origin_by_resource_id_, 537 origin, resource_id)) { 538 sync_type = DISABLED_ORIGIN; 539 } else { 540 return; 541 } 542 543 std::string key = CreateKeyForOriginRoot(origin, sync_type); 544 DCHECK(!key.empty()); 545 546 scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch); 547 batch->Put(key, drive_backend::RemoveWapiIdPrefix(resource_id)); 548 WriteToDB(batch.Pass(), 549 base::Bind(&DriveMetadataStore::UpdateDBStatus, AsWeakPtr())); 550 } 551 552 bool DriveMetadataStore::IsKnownOrigin(const GURL& origin) const { 553 DCHECK(CalledOnValidThread()); 554 return IsIncrementalSyncOrigin(origin) || IsOriginDisabled(origin); 555 } 556 557 bool DriveMetadataStore::IsIncrementalSyncOrigin(const GURL& origin) const { 558 DCHECK(CalledOnValidThread()); 559 return ContainsKey(incremental_sync_origins_, origin); 560 } 561 562 bool DriveMetadataStore::IsOriginDisabled(const GURL& origin) const { 563 DCHECK(CalledOnValidThread()); 564 return ContainsKey(disabled_origins_, origin); 565 } 566 567 void DriveMetadataStore::EnableOrigin( 568 const GURL& origin, 569 const SyncStatusCallback& callback) { 570 DCHECK(CalledOnValidThread()); 571 572 std::map<GURL, std::string>::iterator found = disabled_origins_.find(origin); 573 if (found == disabled_origins_.end()) { 574 RunSoon(FROM_HERE, base::Bind(callback, SYNC_DATABASE_ERROR_NOT_FOUND)); 575 // |origin| has not been registered yet. 576 return; 577 } 578 disabled_origins_.erase(found); 579 580 // |origin| goes back to DriveFileSyncService::pending_batch_sync_origins_ 581 // only and is not stored in drive_metadata_store. 582 found = incremental_sync_origins_.find(origin); 583 if (found != incremental_sync_origins_.end()) 584 incremental_sync_origins_.erase(found); 585 586 scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch); 587 batch->Delete(CreateKeyForOriginRoot(origin, INCREMENTAL_SYNC_ORIGIN)); 588 batch->Delete(CreateKeyForOriginRoot(origin, DISABLED_ORIGIN)); 589 WriteToDB(batch.Pass(), callback); 590 } 591 592 void DriveMetadataStore::DisableOrigin( 593 const GURL& origin, 594 const SyncStatusCallback& callback) { 595 DCHECK(CalledOnValidThread()); 596 597 std::string resource_id; 598 if (!EraseIfExists(&incremental_sync_origins_, origin, &resource_id)) { 599 RunSoon(FROM_HERE, base::Bind(callback, SYNC_DATABASE_ERROR_NOT_FOUND)); 600 return; 601 } 602 disabled_origins_[origin] = resource_id; 603 604 scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch); 605 batch->Delete(CreateKeyForOriginRoot(origin, INCREMENTAL_SYNC_ORIGIN)); 606 batch->Put(CreateKeyForOriginRoot(origin, DISABLED_ORIGIN), 607 drive_backend::RemoveWapiIdPrefix(resource_id)); 608 AppendMetadataDeletionToBatch(metadata_map_, origin, batch.get()); 609 metadata_map_.erase(origin); 610 611 WriteToDB(batch.Pass(), callback); 612 } 613 614 void DriveMetadataStore::RemoveOrigin( 615 const GURL& origin, 616 const SyncStatusCallback& callback) { 617 DCHECK(CalledOnValidThread()); 618 619 std::string resource_id; 620 if (!EraseIfExists(&incremental_sync_origins_, origin, &resource_id) && 621 !EraseIfExists(&disabled_origins_, origin, &resource_id)) { 622 RunSoon(FROM_HERE, base::Bind(callback, SYNC_DATABASE_ERROR_NOT_FOUND)); 623 return; 624 } 625 origin_by_resource_id_.erase(resource_id); 626 627 scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch); 628 batch->Delete(CreateKeyForOriginRoot(origin, INCREMENTAL_SYNC_ORIGIN)); 629 batch->Delete(CreateKeyForOriginRoot(origin, DISABLED_ORIGIN)); 630 AppendMetadataDeletionToBatch(metadata_map_, origin, batch.get()); 631 metadata_map_.erase(origin); 632 633 WriteToDB(batch.Pass(), callback); 634 } 635 636 void DriveMetadataStore::WriteToDB(scoped_ptr<leveldb::WriteBatch> batch, 637 const SyncStatusCallback& callback) { 638 DCHECK(CalledOnValidThread()); 639 if (db_status_ != SYNC_STATUS_OK && 640 db_status_ != SYNC_DATABASE_ERROR_NOT_FOUND) { 641 RunSoon(FROM_HERE, base::Bind(callback, SYNC_DATABASE_ERROR_FAILED)); 642 return; 643 } 644 645 DCHECK(db_); 646 base::PostTaskAndReplyWithResult( 647 file_task_runner_.get(), 648 FROM_HERE, 649 base::Bind(&leveldb::DB::Write, 650 base::Unretained(db_.get()), 651 leveldb::WriteOptions(), 652 base::Owned(batch.release())), 653 base::Bind(&DriveMetadataStore::UpdateDBStatusAndInvokeCallback, 654 AsWeakPtr(), 655 callback)); 656 } 657 658 void DriveMetadataStore::UpdateDBStatus(SyncStatusCode status) { 659 DCHECK(CalledOnValidThread()); 660 if (db_status_ != SYNC_STATUS_OK && 661 db_status_ != SYNC_DATABASE_ERROR_NOT_FOUND) { 662 // TODO(tzik): Handle database corruption. http://crbug.com/153709 663 db_status_ = status; 664 util::Log(logging::LOG_WARNING, 665 FROM_HERE, 666 "DriveMetadataStore turned to wrong state: %s", 667 SyncStatusCodeToString(status)); 668 return; 669 } 670 db_status_ = SYNC_STATUS_OK; 671 } 672 673 void DriveMetadataStore::UpdateDBStatusAndInvokeCallback( 674 const SyncStatusCallback& callback, 675 const leveldb::Status& leveldb_status) { 676 SyncStatusCode status = LevelDBStatusToSyncStatusCode(leveldb_status); 677 UpdateDBStatus(status); 678 callback.Run(status); 679 } 680 681 SyncStatusCode DriveMetadataStore::GetConflictURLs( 682 fileapi::FileSystemURLSet* urls) const { 683 DCHECK(CalledOnValidThread()); 684 DCHECK_EQ(SYNC_STATUS_OK, db_status_); 685 686 urls->clear(); 687 for (MetadataMap::const_iterator origin_itr = metadata_map_.begin(); 688 origin_itr != metadata_map_.end(); 689 ++origin_itr) { 690 for (PathToMetadata::const_iterator itr = origin_itr->second.begin(); 691 itr != origin_itr->second.end(); 692 ++itr) { 693 if (itr->second.conflicted()) { 694 urls->insert(CreateSyncableFileSystemURL( 695 origin_itr->first, itr->first)); 696 } 697 } 698 } 699 return SYNC_STATUS_OK; 700 } 701 702 SyncStatusCode DriveMetadataStore::GetToBeFetchedFiles( 703 URLAndDriveMetadataList* list) const { 704 DCHECK(CalledOnValidThread()); 705 DCHECK_EQ(SYNC_STATUS_OK, db_status_); 706 707 list->clear(); 708 for (MetadataMap::const_iterator origin_itr = metadata_map_.begin(); 709 origin_itr != metadata_map_.end(); 710 ++origin_itr) { 711 for (PathToMetadata::const_iterator itr = origin_itr->second.begin(); 712 itr != origin_itr->second.end(); 713 ++itr) { 714 if (itr->second.to_be_fetched()) { 715 FileSystemURL url = CreateSyncableFileSystemURL( 716 origin_itr->first, itr->first); 717 list->push_back(std::make_pair(url, itr->second)); 718 } 719 } 720 } 721 return SYNC_STATUS_OK; 722 } 723 724 std::string DriveMetadataStore::GetResourceIdForOrigin( 725 const GURL& origin) const { 726 DCHECK(CalledOnValidThread()); 727 728 // If we don't have valid root directory (this could be reset even after 729 // initialized) just return empty string, as the origin directories 730 // in the root directory must have become invalid now too. 731 if (sync_root_directory().empty()) 732 return std::string(); 733 734 ResourceIdByOrigin::const_iterator found = 735 incremental_sync_origins_.find(origin); 736 if (found != incremental_sync_origins_.end()) 737 return found->second; 738 739 found = disabled_origins_.find(origin); 740 if (found != disabled_origins_.end()) 741 return found->second; 742 743 return std::string(); 744 } 745 746 void DriveMetadataStore::GetAllOrigins(std::vector<GURL>* origins) { 747 DCHECK(CalledOnValidThread()); 748 DCHECK(origins); 749 origins->clear(); 750 origins->reserve(incremental_sync_origins_.size() + 751 disabled_origins_.size()); 752 AddOriginsToVector(origins, incremental_sync_origins_); 753 AddOriginsToVector(origins, disabled_origins_); 754 } 755 756 bool DriveMetadataStore::GetOriginByOriginRootDirectoryId( 757 const std::string& resource_id, 758 GURL* origin) { 759 DCHECK(CalledOnValidThread()); 760 DCHECK(origin); 761 762 OriginByResourceId::iterator found = origin_by_resource_id_.find(resource_id); 763 if (found == origin_by_resource_id_.end()) 764 return false; 765 *origin = found->second; 766 return true; 767 } 768 769 scoped_ptr<base::ListValue> DriveMetadataStore::DumpFiles(const GURL& origin) { 770 DCHECK(CalledOnValidThread()); 771 772 scoped_ptr<base::ListValue> files(new base::ListValue); 773 774 MetadataMap::const_iterator found = metadata_map_.find(origin); 775 if (found == metadata_map_.end()) 776 return make_scoped_ptr(new base::ListValue); 777 778 for (PathToMetadata::const_iterator itr = found->second.begin(); 779 itr != found->second.end(); 780 ++itr) { 781 // Convert Drive specific metadata to Common File metadata object. 782 const DriveMetadata& metadata = itr->second; 783 784 base::DictionaryValue* file = new DictionaryValue; 785 file->SetString("path", itr->first.AsUTF8Unsafe()); 786 file->SetString("title", itr->first.BaseName().AsUTF8Unsafe()); 787 file->SetString("type", DriveTypeToString(metadata.type())); 788 789 base::DictionaryValue* details = new DictionaryValue; 790 details->SetString("resource_id", metadata.resource_id()); 791 details->SetString("md5", metadata.md5_checksum()); 792 details->SetString("dirty", metadata.to_be_fetched() ? "true" : "false"); 793 794 file->Set("details", details); 795 files->Append(file); 796 } 797 798 return files.Pass(); 799 } 800 801 } // namespace sync_file_system 802