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

Side by Side Diff: chrome/browser/chromeos/gdata/gdata_files.cc

Issue 10800092: Database support for GDataDirectoryService. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 8 years, 4 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 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/chromeos/gdata/gdata_files.h" 5 #include "chrome/browser/chromeos/gdata/gdata_files.h"
6 6
7 #include <leveldb/db.h>
7 #include <vector> 8 #include <vector>
8 9
9 #include "base/message_loop_proxy.h" 10 #include "base/message_loop_proxy.h"
10 #include "base/platform_file.h" 11 #include "base/platform_file.h"
12 #include "base/string_number_conversions.h"
11 #include "base/string_util.h" 13 #include "base/string_util.h"
12 #include "base/stringprintf.h" 14 #include "base/stringprintf.h"
15 #include "base/sequenced_task_runner.h"
13 #include "base/tracked_objects.h" 16 #include "base/tracked_objects.h"
14 #include "base/utf_string_conversions.h" 17 #include "base/utf_string_conversions.h"
15 #include "chrome/browser/chromeos/gdata/gdata.pb.h" 18 #include "chrome/browser/chromeos/gdata/gdata.pb.h"
16 #include "chrome/browser/chromeos/gdata/gdata_util.h" 19 #include "chrome/browser/chromeos/gdata/gdata_util.h"
17 #include "chrome/browser/chromeos/gdata/gdata_wapi_parser.h" 20 #include "chrome/browser/chromeos/gdata/gdata_wapi_parser.h"
21 #include "content/public/browser/browser_thread.h"
18 #include "net/base/escape.h" 22 #include "net/base/escape.h"
19 23
24 using content::BrowserThread;
25
20 namespace gdata { 26 namespace gdata {
21 namespace { 27 namespace {
22 28
23 const char kSlash[] = "/"; 29 const char kSlash[] = "/";
24 const char kEscapedSlash[] = "\xE2\x88\x95"; 30 const char kEscapedSlash[] = "\xE2\x88\x95";
25 31
26 // Extracts resource_id out of edit url. 32 // Extracts resource_id out of edit url.
27 std::string ExtractResourceId(const GURL& url) { 33 std::string ExtractResourceId(const GURL& url) {
28 return net::UnescapeURLComponent(url.ExtractFileName(), 34 return net::UnescapeURLComponent(url.ExtractFileName(),
29 net::UnescapeRule::URL_SPECIAL_CHARS); 35 net::UnescapeRule::URL_SPECIAL_CHARS);
(...skipping 386 matching lines...) Expand 10 before | Expand all | Expand 10 after
416 GDataDirectory* dir = iter->second; 422 GDataDirectory* dir = iter->second;
417 // Remove directories recursively. 423 // Remove directories recursively.
418 dir->RemoveChildren(); 424 dir->RemoveChildren();
419 if (directory_service_) 425 if (directory_service_)
420 directory_service_->RemoveEntryFromResourceMap(dir); 426 directory_service_->RemoveEntryFromResourceMap(dir);
421 } 427 }
422 STLDeleteValues(&child_directories_); 428 STLDeleteValues(&child_directories_);
423 child_directories_.clear(); 429 child_directories_.clear();
424 } 430 }
425 431
432 // GDataDirectoryServiceDB implementation.
433
434 // Params for GDatadirectoryServiceDB::Create.
435 struct CreateDBParams {
436 CreateDBParams(const FilePath& db_path,
437 base::SequencedTaskRunner* blocking_task_runner)
438 : db_path(db_path),
439 blocking_task_runner(blocking_task_runner) {
440 }
441
442 FilePath db_path;
443 base::SequencedTaskRunner* blocking_task_runner;
444 scoped_ptr<GDataDirectoryServiceDB> db;
445 GDataDirectoryService::SerializedMap serialized_resources;
446 };
447
448 // Wrapper for level db. All methods must be called on blocking thread.
449 class GDataDirectoryServiceDB {
450 public:
451 // Creates, initializes and reads from the database.
452 static void Create(CreateDBParams* params);
453
454 // Save |serialized_resources| to the database.
satorux1 2012/08/02 17:24:03 Saves
achuithb 2012/08/02 20:26:25 Done.
455 void Save(const GDataDirectoryService::SerializedMap& serialized_resources);
456
457 private:
458 // Private ctor accessed through Create.
459 GDataDirectoryServiceDB(const FilePath& db_path,
460 base::SequencedTaskRunner* blocking_task_runner);
461
462 // Initialize the database.
satorux1 2012/08/02 17:24:03 Initializes
achuithb 2012/08/02 20:26:25 Done.
463 void Init();
464
465 // Read the database into |serialized_resources|.
satorux1 2012/08/02 17:24:03 ditto
achuithb 2012/08/02 20:26:25 Done.
466 void Read(GDataDirectoryService::SerializedMap* serialized_resources);
467
468 // Truncate the database.
satorux1 2012/08/02 17:24:03 ditto
achuithb 2012/08/02 20:26:25 Done.
469 void Truncate();
satorux1 2012/08/02 17:24:03 Truncating a DB sounds rather awkward, as Truncate
achuithb 2012/08/02 20:26:25 Done.
470
471 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
472 scoped_ptr<leveldb::DB> level_db_;
473 FilePath db_path_;
474 };
475
476 GDataDirectoryServiceDB::GDataDirectoryServiceDB(const FilePath& db_path,
477 base::SequencedTaskRunner* blocking_task_runner)
478 : blocking_task_runner_(blocking_task_runner),
479 db_path_(db_path) {
480 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread());
481 }
482
483 // static
484 void GDataDirectoryServiceDB::Create(CreateDBParams* params) {
satorux1 2012/08/02 17:24:03 I was confused about this function because of the
achuithb 2012/08/02 20:26:25 I renamed the function, but it needs to be defined
485 DCHECK(params->blocking_task_runner->RunsTasksOnCurrentThread());
486 DCHECK(!params->db_path.empty());
487
488 params->db.reset(new GDataDirectoryServiceDB(params->db_path,
489 params->blocking_task_runner));
490 params->db->Init();
491 params->db->Read(&params->serialized_resources);
492 }
493
494
495 void GDataDirectoryServiceDB::Init() {
496 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread());
497 DCHECK(!db_path_.empty());
498
499 DVLOG(1) << "Init " << db_path_.value();
500
501 leveldb::DB* level_db = NULL;
502 leveldb::Options options;
503 options.create_if_missing = true;
504 leveldb::Status db_status = leveldb::DB::Open(options, db_path_.value(),
505 &level_db);
506 DCHECK(level_db);
507 DCHECK(db_status.ok());
508 level_db_.reset(level_db);
509 }
510
511 void GDataDirectoryServiceDB::Read(
512 GDataDirectoryService::SerializedMap* serialized_resources) {
513 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread());
514 DVLOG(1) << "Read " << db_path_.value();
515
516 if (serialized_resources) {
satorux1 2012/08/02 17:24:03 can this be null? DCHECK(serialized_resources); i
achuithb 2012/08/02 20:26:25 Done.
517 scoped_ptr<leveldb::Iterator> iter(level_db_->NewIterator(
518 leveldb::ReadOptions()));
519 for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
520 DVLOG(1) << "Read, resource " << iter->key().ToString();
521 serialized_resources->insert(std::make_pair(iter->key().ToString(),
522 iter->value().ToString()));
523 }
524 }
525 }
526
527 void GDataDirectoryServiceDB::Save(
528 const GDataDirectoryService::SerializedMap& serialized_resources) {
529 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread());
530
531 Truncate();
532 for (GDataDirectoryService::SerializedMap::const_iterator iter =
533 serialized_resources.begin();
534 iter != serialized_resources.end(); ++iter) {
535 DVLOG(1) << "Saving resource " << iter->first << " to db";
536 level_db_->Put(leveldb::WriteOptions(),
537 leveldb::Slice(iter->first),
538 leveldb::Slice(iter->second));
539 }
540 }
541
542 void GDataDirectoryServiceDB::Truncate() {
543 level_db_.reset();
544 leveldb::DestroyDB(db_path_.value(), leveldb::Options());
545 Init();
546 }
547
426 // GDataDirectoryService class implementation. 548 // GDataDirectoryService class implementation.
427 549
428 GDataDirectoryService::GDataDirectoryService() 550 GDataDirectoryService::GDataDirectoryService()
429 : serialized_size_(0), 551 : blocking_task_runner_(NULL),
552 serialized_size_(0),
430 largest_changestamp_(0), 553 largest_changestamp_(0),
431 origin_(UNINITIALIZED) { 554 origin_(UNINITIALIZED),
555 ui_weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
432 root_.reset(new GDataDirectory(NULL, this)); 556 root_.reset(new GDataDirectory(NULL, this));
433 root_->set_title(kGDataRootDirectory); 557 root_->set_title(kGDataRootDirectory);
434 root_->SetBaseNameFromTitle(); 558 root_->SetBaseNameFromTitle();
435 root_->set_resource_id(kGDataRootDirectoryResourceId); 559 root_->set_resource_id(kGDataRootDirectoryResourceId);
436 AddEntryToResourceMap(root_.get()); 560 AddEntryToResourceMap(root_.get());
437 } 561 }
438 562
439 GDataDirectoryService::~GDataDirectoryService() { 563 GDataDirectoryService::~GDataDirectoryService() {
564 ClearRoot();
565
566 // Ensure db is closed on the blocking pool.
567 if (blocking_task_runner_ && directory_service_db_.get())
568 blocking_task_runner_->PostTask(FROM_HERE,
569 base::Bind(&base::DeletePointer<GDataDirectoryServiceDB>,
570 directory_service_db_.release()));
571 }
572
573 void GDataDirectoryService::ClearRoot() {
440 // Note that children have a reference to root_, 574 // Note that children have a reference to root_,
441 // so we need to delete them here. 575 // so we need to delete them here.
442 root_->RemoveChildren(); 576 root_->RemoveChildren();
443 RemoveEntryFromResourceMap(root_.get()); 577 RemoveEntryFromResourceMap(root_.get());
444 DCHECK(resource_map_.empty()); 578 DCHECK(resource_map_.empty());
445 resource_map_.clear(); 579 resource_map_.clear();
580 root_.reset();
446 } 581 }
447 582
448 void GDataDirectoryService::AddEntryToDirectory( 583 void GDataDirectoryService::AddEntryToDirectory(
449 const FilePath& directory_path, 584 const FilePath& directory_path,
450 GDataEntry* entry, 585 GDataEntry* entry,
451 const FileOperationCallback& callback) { 586 const FileOperationCallback& callback) {
452 GDataEntry* destination = FindEntryByPathSync(directory_path); 587 GDataEntry* destination = FindEntryByPathSync(directory_path);
453 GDataFileError error = GDATA_FILE_ERROR_FAILED; 588 GDataFileError error = GDATA_FILE_ERROR_FAILED;
454 if (!destination) { 589 if (!destination) {
455 error = GDATA_FILE_ERROR_NOT_FOUND; 590 error = GDATA_FILE_ERROR_NOT_FOUND;
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
547 GDataDirectory* entry_parent = old_entry ? old_entry->parent() : NULL; 682 GDataDirectory* entry_parent = old_entry ? old_entry->parent() : NULL;
548 if (entry_parent) { 683 if (entry_parent) {
549 DCHECK_EQ(fresh_file->resource_id(), old_entry->resource_id()); 684 DCHECK_EQ(fresh_file->resource_id(), old_entry->resource_id());
550 DCHECK(old_entry->AsGDataFile()); 685 DCHECK(old_entry->AsGDataFile());
551 686
552 entry_parent->RemoveEntry(old_entry); 687 entry_parent->RemoveEntry(old_entry);
553 entry_parent->AddEntry(fresh_file.release()); 688 entry_parent->AddEntry(fresh_file.release());
554 } 689 }
555 } 690 }
556 691
692 void GDataDirectoryService::InitFromDB(
693 const FilePath& db_path,
694 base::SequencedTaskRunner* blocking_task_runner,
695 LoadRootFeedParams* load_params,
696 const base::Closure& callback) {
697 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
698 DCHECK(!db_path.empty());
699 DCHECK(blocking_task_runner);
700
701 if (directory_service_db_.get()) {
702 NOTREACHED();
703 if (!callback.is_null())
704 callback.Run();
705 }
706
707 blocking_task_runner_ = blocking_task_runner;
708
709 DVLOG(1) << "InitFromDB " << db_path.value();
710
711 CreateDBParams* create_params =
712 new CreateDBParams(db_path, blocking_task_runner);
713 blocking_task_runner_->PostTaskAndReply(
714 FROM_HERE,
715 base::Bind(&GDataDirectoryServiceDB::Create,
716 create_params),
717 base::Bind(&GDataDirectoryService::InitResourceMap,
718 ui_weak_ptr_factory_.GetWeakPtr(),
719 base::Owned(create_params),
720 load_params,
721 callback));
722 }
723
724 void GDataDirectoryService::InitResourceMap(
725 CreateDBParams* create_params,
726 LoadRootFeedParams* load_params,
727 const base::Closure& callback) {
728 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
729 DCHECK(create_params);
730
731 directory_service_db_ = create_params->db.Pass();
732 if (create_params->serialized_resources.empty()) {
733 origin_ = INITIALIZING;
734 if (load_params)
735 load_params->load_error = GDATA_FILE_ERROR_NOT_FOUND;
736 if (!callback.is_null())
737 callback.Run();
738 return;
739 }
740
741 ClearRoot();
742
743 int32 version = 0;
744 ResourceMap resource_map;
745 for (SerializedMap::const_iterator iter =
746 create_params->serialized_resources.begin();
747 iter != create_params->serialized_resources.end(); ++iter) {
748 if (iter->first == "version") {
749 if (!base::StringToInt(iter->second, &version) ||
750 version != kProtoVersion) {
751 if (!callback.is_null())
752 callback.Run();
753 return;
754 }
755 continue;
756 }
757
758 if (iter->first == "largest_changestamp") {
759 base::StringToInt(iter->second, &largest_changestamp_);
760 DVLOG(1) << "InitResourceMap largest_changestamp_"
761 << largest_changestamp_;
762 continue;
763 }
764
765 scoped_ptr<GDataEntry> entry = FromProtoString(iter->second);
766 if (entry.get()) {
767 DVLOG(1) << "Inserting resource " << iter->first
768 << " into resource_map";
769 resource_map.insert(std::make_pair(iter->first, entry.release()));
770 } else {
771 NOTREACHED() << "Failed to parse GDataEntry for resource "
772 << iter->first;
773 }
774 }
775
776 // Fix up parent-child relations.
777 for (ResourceMap::iterator iter = resource_map.begin();
778 iter != resource_map.end(); ++iter) {
779 GDataEntry* entry = iter->second;
780 ResourceMap::iterator parent_it =
781 resource_map.find(entry->parent_resource_id());
782 if (parent_it != resource_map.end()) {
783 GDataDirectory* parent = parent_it->second->AsGDataDirectory();
784 if (parent) {
785 DVLOG(1) << "Adding " << entry->resource_id()
786 << " as a child of " << parent->resource_id();
787 parent->AddEntry(entry);
788 } else {
789 NOTREACHED() << "Parent is not a directory " << parent->resource_id();
790 }
791 } else if (entry->resource_id() == kGDataRootDirectoryResourceId) {
792 root_.reset(entry->AsGDataDirectory());
793 DCHECK(root_.get());
794 AddEntryToResourceMap(root_.get());
795 } else {
796 NOTREACHED() << "Missing parent id " << entry->parent_resource_id()
797 << " for resource " << entry->resource_id();
798 }
799 }
800
801 DCHECK(root_.get());
802 DCHECK_EQ(resource_map.size(), resource_map_.size());
803 DCHECK_EQ(resource_map.size(),
804 create_params->serialized_resources.size() - 2);
805
806 origin_ = FROM_CACHE;
807
808 if (!callback.is_null())
809 callback.Run();
810 }
811
812 void GDataDirectoryService::SaveToDB() {
813 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
814
815 if (!blocking_task_runner_ || !directory_service_db_.get()) {
816 NOTREACHED();
817 return;
818 }
819
820 size_t serialized_size = 0;
821 SerializedMap serialized_resources;
822 for (ResourceMap::const_iterator iter = resource_map_.begin();
823 iter != resource_map_.end(); ++iter) {
824 GDataEntryProto proto;
825 iter->second->ToProtoFull(&proto);
826 std::string serialized_string;
827 const bool ok = proto.SerializeToString(&serialized_string);
828 DCHECK(ok);
829 if (ok) {
830 serialized_resources.insert(
831 std::make_pair(iter->first, serialized_string));
832 serialized_size += serialized_string.size();
833 }
834 }
835
836 serialized_resources.insert(
837 std::make_pair("version",
satorux1 2012/08/02 17:24:03 the indentation is awkard. 4 spaces from the previ
achuithb 2012/08/02 20:26:25 Done.
838 base::IntToString(kProtoVersion)));
839 serialized_resources.insert(
840 std::make_pair("largest_changestamp",
satorux1 2012/08/02 17:24:03 ditto.
achuithb 2012/08/02 20:26:25 Done.
841 base::IntToString(largest_changestamp_)));
842 set_last_serialized(base::Time::Now());
843 set_serialized_size(serialized_size);
844
845 blocking_task_runner_->PostTask(
846 FROM_HERE,
847 base::Bind(&GDataDirectoryServiceDB::Save,
848 base::Unretained(directory_service_db_.get()),
849 serialized_resources));
850 }
851
557 // Convert to/from proto. 852 // Convert to/from proto.
558 853
559 // static 854 // static
560 void GDataEntry::ConvertProtoToPlatformFileInfo( 855 void GDataEntry::ConvertProtoToPlatformFileInfo(
561 const PlatformFileInfoProto& proto, 856 const PlatformFileInfoProto& proto,
562 base::PlatformFileInfo* file_info) { 857 base::PlatformFileInfo* file_info) {
563 file_info->size = proto.size(); 858 file_info->size = proto.size();
564 file_info->is_directory = proto.is_directory(); 859 file_info->is_directory = proto.is_directory();
565 file_info->is_symbolic_link = proto.is_symbolic_link(); 860 file_info->is_symbolic_link = proto.is_symbolic_link();
566 file_info->last_modified = base::Time::FromInternalValue( 861 file_info->last_modified = base::Time::FromInternalValue(
(...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after
781 1076
782 if (!root_->FromProto(proto.gdata_directory())) 1077 if (!root_->FromProto(proto.gdata_directory()))
783 return false; 1078 return false;
784 1079
785 origin_ = FROM_CACHE; 1080 origin_ = FROM_CACHE;
786 largest_changestamp_ = proto.largest_changestamp(); 1081 largest_changestamp_ = proto.largest_changestamp();
787 1082
788 return true; 1083 return true;
789 } 1084 }
790 1085
1086 scoped_ptr<GDataEntry> GDataDirectoryService::FromProtoString(
1087 const std::string& serialized_proto) {
1088 scoped_ptr<GDataEntry> entry;
1089
1090 GDataEntryProto entry_proto;
1091 if (!entry_proto.ParseFromString(serialized_proto))
1092 return entry.Pass();
1093
1094 if (entry_proto.file_info().is_directory()) {
1095 entry.reset(new GDataDirectory(NULL, this));
1096 // Call GDataEntry::FromProto.
1097 if (!entry->FromProto(entry_proto)) {
1098 NOTREACHED() << "FromProto (directory) failed";
1099 entry.reset();
1100 }
1101 } else {
1102 scoped_ptr<GDataFile> file(new GDataFile(NULL, this));
1103 // Call GDataFile::FromProto.
1104 if (file->FromProto(entry_proto)) {
1105 entry.reset(file.release());
1106 } else {
1107 NOTREACHED() << "FromProto (file) failed";
1108 }
1109 }
1110 return entry.Pass();
1111 }
1112
791 } // namespace gdata 1113 } // namespace gdata
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698