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