OLD | NEW |
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/drive/drive_resource_metadata.h" | 5 #include "chrome/browser/chromeos/drive/drive_resource_metadata.h" |
6 | 6 |
7 #include <leveldb/db.h> | 7 #include <leveldb/db.h> |
8 #include <stack> | 8 #include <stack> |
9 #include <utility> | 9 #include <utility> |
10 | 10 |
11 #include "base/message_loop_proxy.h" | 11 #include "base/message_loop_proxy.h" |
12 #include "base/strings/string_number_conversions.h" | 12 #include "base/strings/string_number_conversions.h" |
13 #include "chrome/browser/chromeos/drive/drive.pb.h" | 13 #include "chrome/browser/chromeos/drive/drive.pb.h" |
14 #include "chrome/browser/chromeos/drive/drive_files.h" | 14 #include "chrome/browser/chromeos/drive/drive_files.h" |
15 #include "content/public/browser/browser_thread.h" | 15 #include "content/public/browser/browser_thread.h" |
16 | 16 |
17 using content::BrowserThread; | 17 using content::BrowserThread; |
18 | 18 |
19 namespace drive { | 19 namespace drive { |
20 namespace { | 20 namespace { |
21 | 21 |
22 // m: prefix for filesystem metadata db keys, version and largest_changestamp. | |
23 // r: prefix for resource id db keys. | |
24 const char kDBKeyLargestChangestamp[] = "m:largest_changestamp"; | |
25 const char kDBKeyVersion[] = "m:version"; | |
26 const char kDBKeyResourceIdPrefix[] = "r:"; | |
27 | |
28 // Posts |error| to |callback| asynchronously. |callback| must not be null. | 22 // Posts |error| to |callback| asynchronously. |callback| must not be null. |
29 void PostFileMoveCallbackError(const FileMoveCallback& callback, | 23 void PostFileMoveCallbackError(const FileMoveCallback& callback, |
30 DriveFileError error) { | 24 DriveFileError error) { |
31 base::MessageLoopProxy::current()->PostTask( | 25 base::MessageLoopProxy::current()->PostTask( |
32 FROM_HERE, | 26 FROM_HERE, |
33 base::Bind(callback, error, base::FilePath())); | 27 base::Bind(callback, error, base::FilePath())); |
34 } | 28 } |
35 | 29 |
36 // Posts |error| to |callback| asynchronously. |callback| must not be null. | 30 // Posts |error| to |callback| asynchronously. |callback| must not be null. |
37 void PostGetEntryInfoWithFilePathCallbackError( | 31 void PostGetEntryInfoWithFilePathCallbackError( |
(...skipping 26 matching lines...) Expand all Loading... |
64 | 58 |
65 EntryInfoResult::~EntryInfoResult() { | 59 EntryInfoResult::~EntryInfoResult() { |
66 } | 60 } |
67 | 61 |
68 EntryInfoPairResult::EntryInfoPairResult() { | 62 EntryInfoPairResult::EntryInfoPairResult() { |
69 } | 63 } |
70 | 64 |
71 EntryInfoPairResult::~EntryInfoPairResult() { | 65 EntryInfoPairResult::~EntryInfoPairResult() { |
72 } | 66 } |
73 | 67 |
74 // ResourceMetadataDB implementation. | |
75 | |
76 // Params for ResourceMetadataDB::Create. | |
77 struct CreateDBParams { | |
78 CreateDBParams(const base::FilePath& db_path, | |
79 base::SequencedTaskRunner* blocking_task_runner) | |
80 : db_path(db_path), | |
81 blocking_task_runner(blocking_task_runner) { | |
82 } | |
83 | |
84 base::FilePath db_path; | |
85 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner; | |
86 scoped_ptr<ResourceMetadataDB> db; | |
87 DriveResourceMetadata::SerializedMap serialized_resources; | |
88 }; | |
89 | |
90 // Wrapper for level db. All methods must be called on blocking thread. | |
91 class ResourceMetadataDB { | |
92 public: | |
93 ResourceMetadataDB(const base::FilePath& db_path, | |
94 base::SequencedTaskRunner* blocking_task_runner); | |
95 | |
96 // Initializes the database. | |
97 void Init(); | |
98 | |
99 // Reads the database into |serialized_resources|. | |
100 void Read(DriveResourceMetadata::SerializedMap* serialized_resources); | |
101 | |
102 // Saves |serialized_resources| to the database. | |
103 void Save(const DriveResourceMetadata::SerializedMap& serialized_resources); | |
104 | |
105 private: | |
106 // Clears the database. | |
107 void Clear(); | |
108 | |
109 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_; | |
110 scoped_ptr<leveldb::DB> level_db_; | |
111 base::FilePath db_path_; | |
112 }; | |
113 | |
114 ResourceMetadataDB::ResourceMetadataDB(const base::FilePath& db_path, | |
115 base::SequencedTaskRunner* blocking_task_runner) | |
116 : blocking_task_runner_(blocking_task_runner), | |
117 db_path_(db_path) { | |
118 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); | |
119 } | |
120 | |
121 // Creates, initializes and reads from the database. | |
122 // This must be defined after ResourceMetadataDB and CreateDBParams. | |
123 static void CreateResourceMetadataDBOnBlockingPool( | |
124 CreateDBParams* params) { | |
125 DCHECK(params->blocking_task_runner->RunsTasksOnCurrentThread()); | |
126 DCHECK(!params->db_path.empty()); | |
127 | |
128 params->db.reset(new ResourceMetadataDB(params->db_path, | |
129 params->blocking_task_runner)); | |
130 params->db->Init(); | |
131 params->db->Read(¶ms->serialized_resources); | |
132 } | |
133 | |
134 void ResourceMetadataDB::Init() { | |
135 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); | |
136 DCHECK(!db_path_.empty()); | |
137 | |
138 DVLOG(1) << "Init " << db_path_.value(); | |
139 | |
140 leveldb::DB* level_db = NULL; | |
141 leveldb::Options options; | |
142 options.create_if_missing = true; | |
143 leveldb::Status db_status = leveldb::DB::Open(options, db_path_.value(), | |
144 &level_db); | |
145 DCHECK(level_db); | |
146 DCHECK(db_status.ok()); | |
147 level_db_.reset(level_db); | |
148 } | |
149 | |
150 void ResourceMetadataDB::Read( | |
151 DriveResourceMetadata::SerializedMap* serialized_resources) { | |
152 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); | |
153 DCHECK(serialized_resources); | |
154 DVLOG(1) << "Read " << db_path_.value(); | |
155 | |
156 scoped_ptr<leveldb::Iterator> iter(level_db_->NewIterator( | |
157 leveldb::ReadOptions())); | |
158 for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { | |
159 DVLOG(1) << "Read, resource " << iter->key().ToString(); | |
160 serialized_resources->insert(std::make_pair(iter->key().ToString(), | |
161 iter->value().ToString())); | |
162 } | |
163 } | |
164 | |
165 void ResourceMetadataDB::Save( | |
166 const DriveResourceMetadata::SerializedMap& serialized_resources) { | |
167 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); | |
168 | |
169 Clear(); | |
170 for (DriveResourceMetadata::SerializedMap::const_iterator iter = | |
171 serialized_resources.begin(); | |
172 iter != serialized_resources.end(); ++iter) { | |
173 DVLOG(1) << "Saving resource " << iter->first << " to db"; | |
174 leveldb::Status status = level_db_->Put(leveldb::WriteOptions(), | |
175 leveldb::Slice(iter->first), | |
176 leveldb::Slice(iter->second)); | |
177 if (!status.ok()) { | |
178 LOG(ERROR) << "leveldb Put failed of " << iter->first | |
179 << ", with " << status.ToString(); | |
180 NOTREACHED(); | |
181 } | |
182 } | |
183 } | |
184 | |
185 void ResourceMetadataDB::Clear() { | |
186 level_db_.reset(); | |
187 leveldb::DestroyDB(db_path_.value(), leveldb::Options()); | |
188 Init(); | |
189 } | |
190 | |
191 // DriveResourceMetadata class implementation. | 68 // DriveResourceMetadata class implementation. |
192 | 69 |
193 DriveResourceMetadata::DriveResourceMetadata( | 70 DriveResourceMetadata::DriveResourceMetadata( |
194 const std::string& root_resource_id) | 71 const std::string& root_resource_id) |
195 : blocking_task_runner_(NULL), | 72 : blocking_task_runner_(NULL), |
196 serialized_size_(0), | 73 serialized_size_(0), |
197 largest_changestamp_(0), | 74 largest_changestamp_(0), |
198 loaded_(false), | 75 loaded_(false), |
199 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) { | 76 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) { |
200 root_ = CreateDriveDirectory().Pass(); | 77 root_ = CreateDriveDirectory().Pass(); |
201 root_->set_resource_id(root_resource_id); | 78 root_->set_resource_id(root_resource_id); |
202 root_->set_title(kDriveRootDirectory); | 79 root_->set_title(kDriveRootDirectory); |
203 root_->SetBaseNameFromTitle(); | 80 root_->SetBaseNameFromTitle(); |
204 | 81 |
205 AddEntryToResourceMap(root_.get()); | 82 AddEntryToResourceMap(root_.get()); |
206 } | 83 } |
207 | 84 |
208 DriveResourceMetadata::~DriveResourceMetadata() { | 85 DriveResourceMetadata::~DriveResourceMetadata() { |
209 ClearRoot(); | 86 ClearRoot(); |
210 | |
211 // Ensure db is closed on the blocking pool. | |
212 if (blocking_task_runner_ && resource_metadata_db_.get()) | |
213 blocking_task_runner_->DeleteSoon(FROM_HERE, | |
214 resource_metadata_db_.release()); | |
215 } | 87 } |
216 | 88 |
217 scoped_ptr<DriveEntry> DriveResourceMetadata::CreateDriveEntry() { | 89 scoped_ptr<DriveEntry> DriveResourceMetadata::CreateDriveEntry() { |
218 return scoped_ptr<DriveEntry>(new DriveEntry(this)); | 90 return scoped_ptr<DriveEntry>(new DriveEntry(this)); |
219 } | 91 } |
220 | 92 |
221 scoped_ptr<DriveDirectory> DriveResourceMetadata::CreateDriveDirectory() { | 93 scoped_ptr<DriveDirectory> DriveResourceMetadata::CreateDriveDirectory() { |
222 return scoped_ptr<DriveDirectory>(new DriveDirectory(this)); | 94 return scoped_ptr<DriveDirectory>(new DriveDirectory(this)); |
223 } | 95 } |
224 | 96 |
(...skipping 415 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
640 base::MessageLoopProxy::current()->PostTask( | 512 base::MessageLoopProxy::current()->PostTask( |
641 FROM_HERE, | 513 FROM_HERE, |
642 base::Bind(changed_dirs_callback, changed_directories)); | 514 base::Bind(changed_dirs_callback, changed_directories)); |
643 } | 515 } |
644 | 516 |
645 void DriveResourceMetadata::RemoveAll(const base::Closure& callback) { | 517 void DriveResourceMetadata::RemoveAll(const base::Closure& callback) { |
646 root_->RemoveChildren(); | 518 root_->RemoveChildren(); |
647 base::MessageLoopProxy::current()->PostTask(FROM_HERE, callback); | 519 base::MessageLoopProxy::current()->PostTask(FROM_HERE, callback); |
648 } | 520 } |
649 | 521 |
650 void DriveResourceMetadata::InitFromDB( | |
651 const base::FilePath& db_path, | |
652 base::SequencedTaskRunner* blocking_task_runner, | |
653 const FileOperationCallback& callback) { | |
654 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
655 DCHECK(!db_path.empty()); | |
656 DCHECK(blocking_task_runner); | |
657 DCHECK(!callback.is_null()); | |
658 | |
659 if (resource_metadata_db_.get()) { | |
660 callback.Run(DRIVE_FILE_ERROR_IN_USE); | |
661 return; | |
662 } | |
663 | |
664 blocking_task_runner_ = blocking_task_runner; | |
665 | |
666 DVLOG(1) << "InitFromDB " << db_path.value(); | |
667 | |
668 CreateDBParams* create_params = | |
669 new CreateDBParams(db_path, blocking_task_runner); | |
670 blocking_task_runner_->PostTaskAndReply( | |
671 FROM_HERE, | |
672 base::Bind(&CreateResourceMetadataDBOnBlockingPool, | |
673 create_params), | |
674 base::Bind(&DriveResourceMetadata::InitResourceMap, | |
675 weak_ptr_factory_.GetWeakPtr(), | |
676 base::Owned(create_params), | |
677 callback)); | |
678 } | |
679 | |
680 void DriveResourceMetadata::InitResourceMap( | |
681 CreateDBParams* create_params, | |
682 const FileOperationCallback& callback) { | |
683 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
684 DCHECK(create_params); | |
685 DCHECK(!resource_metadata_db_.get()); | |
686 DCHECK(!callback.is_null()); | |
687 | |
688 SerializedMap* serialized_resources = &create_params->serialized_resources; | |
689 resource_metadata_db_ = create_params->db.Pass(); | |
690 if (serialized_resources->empty()) { | |
691 callback.Run(DRIVE_FILE_ERROR_NOT_FOUND); | |
692 return; | |
693 } | |
694 | |
695 // Save root directory resource ID as ClearRoot() resets |root_|. | |
696 std::string saved_root_resource_id = root_->resource_id(); | |
697 ClearRoot(); | |
698 | |
699 // Version check. | |
700 int32 version = 0; | |
701 SerializedMap::iterator iter = serialized_resources->find(kDBKeyVersion); | |
702 if (iter == serialized_resources->end() || | |
703 !base::StringToInt(iter->second, &version) || | |
704 version != kProtoVersion) { | |
705 callback.Run(DRIVE_FILE_ERROR_FAILED); | |
706 return; | |
707 } | |
708 serialized_resources->erase(iter); | |
709 | |
710 // Get the largest changestamp. | |
711 iter = serialized_resources->find(kDBKeyLargestChangestamp); | |
712 if (iter == serialized_resources->end() || | |
713 !base::StringToInt64(iter->second, &largest_changestamp_)) { | |
714 NOTREACHED() << "Could not find/parse largest_changestamp"; | |
715 callback.Run(DRIVE_FILE_ERROR_FAILED); | |
716 return; | |
717 } else { | |
718 DVLOG(1) << "InitResourceMap largest_changestamp_" << largest_changestamp_; | |
719 serialized_resources->erase(iter); | |
720 } | |
721 | |
722 ResourceMap resource_map; | |
723 for (SerializedMap::const_iterator iter = serialized_resources->begin(); | |
724 iter != serialized_resources->end(); ++iter) { | |
725 if (iter->first.find(kDBKeyResourceIdPrefix) != 0) { | |
726 NOTREACHED() << "Incorrect prefix for db key " << iter->first; | |
727 continue; | |
728 } | |
729 | |
730 const std::string resource_id = | |
731 iter->first.substr(strlen(kDBKeyResourceIdPrefix)); | |
732 scoped_ptr<DriveEntry> entry = | |
733 CreateDriveEntryFromProtoString(iter->second); | |
734 if (entry.get()) { | |
735 DVLOG(1) << "Inserting resource " << resource_id | |
736 << " into resource_map"; | |
737 resource_map.insert(std::make_pair(resource_id, entry.release())); | |
738 } else { | |
739 NOTREACHED() << "Failed to parse DriveEntry for resource " << resource_id; | |
740 } | |
741 } | |
742 | |
743 // Fix up parent-child relations. | |
744 for (ResourceMap::iterator iter = resource_map.begin(); | |
745 iter != resource_map.end(); ++iter) { | |
746 DriveEntry* entry = iter->second; | |
747 ResourceMap::iterator parent_it = | |
748 resource_map.find(entry->parent_resource_id()); | |
749 if (parent_it != resource_map.end()) { | |
750 DriveDirectory* parent = parent_it->second->AsDriveDirectory(); | |
751 if (parent) { | |
752 DVLOG(1) << "Adding " << entry->resource_id() | |
753 << " as a child of " << parent->resource_id(); | |
754 parent->AddEntry(entry); | |
755 } else { | |
756 NOTREACHED() << "Parent is not a directory " << parent->resource_id(); | |
757 } | |
758 } else if (entry->resource_id() == saved_root_resource_id) { | |
759 root_.reset(entry->AsDriveDirectory()); | |
760 DCHECK(root_.get()); | |
761 AddEntryToResourceMap(root_.get()); | |
762 } else { | |
763 NOTREACHED() << "Missing parent id " << entry->parent_resource_id() | |
764 << " for resource " << entry->resource_id(); | |
765 } | |
766 } | |
767 | |
768 if (!root_.get()) { | |
769 // TODO(achuith): Initialize |root_| before return. | |
770 callback.Run(DRIVE_FILE_ERROR_FAILED); | |
771 return; | |
772 } | |
773 DCHECK_EQ(resource_map.size(), resource_map_.size()); | |
774 DCHECK_EQ(resource_map.size(), serialized_resources->size()); | |
775 | |
776 loaded_ = true; | |
777 | |
778 callback.Run(DRIVE_FILE_OK); | |
779 } | |
780 | |
781 void DriveResourceMetadata::SaveToDB() { | |
782 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
783 | |
784 if (!blocking_task_runner_ || !resource_metadata_db_.get()) { | |
785 NOTREACHED(); | |
786 return; | |
787 } | |
788 | |
789 size_t serialized_size = 0; | |
790 SerializedMap serialized_resources; | |
791 for (ResourceMap::const_iterator iter = resource_map_.begin(); | |
792 iter != resource_map_.end(); ++iter) { | |
793 const DriveEntryProto& proto = iter->second->proto(); | |
794 std::string serialized_string; | |
795 const bool ok = proto.SerializeToString(&serialized_string); | |
796 DCHECK(ok); | |
797 if (ok) { | |
798 serialized_resources.insert( | |
799 std::make_pair(std::string(kDBKeyResourceIdPrefix) + iter->first, | |
800 serialized_string)); | |
801 serialized_size += serialized_string.size(); | |
802 } | |
803 } | |
804 | |
805 serialized_resources.insert(std::make_pair(kDBKeyVersion, | |
806 base::IntToString(kProtoVersion))); | |
807 serialized_resources.insert(std::make_pair(kDBKeyLargestChangestamp, | |
808 base::IntToString(largest_changestamp_))); | |
809 set_last_serialized(base::Time::Now()); | |
810 set_serialized_size(serialized_size); | |
811 | |
812 blocking_task_runner_->PostTask( | |
813 FROM_HERE, | |
814 base::Bind(&ResourceMetadataDB::Save, | |
815 base::Unretained(resource_metadata_db_.get()), | |
816 serialized_resources)); | |
817 } | |
818 | |
819 void DriveResourceMetadata::SerializeToString( | 522 void DriveResourceMetadata::SerializeToString( |
820 std::string* serialized_proto) const { | 523 std::string* serialized_proto) const { |
821 DriveRootDirectoryProto proto; | 524 DriveRootDirectoryProto proto; |
822 root_->ToProto(proto.mutable_drive_directory()); | 525 root_->ToProto(proto.mutable_drive_directory()); |
823 proto.set_largest_changestamp(largest_changestamp_); | 526 proto.set_largest_changestamp(largest_changestamp_); |
824 proto.set_version(kProtoVersion); | 527 proto.set_version(kProtoVersion); |
825 | 528 |
826 const bool ok = proto.SerializeToString(serialized_proto); | 529 const bool ok = proto.SerializeToString(serialized_proto); |
827 DCHECK(ok); | 530 DCHECK(ok); |
828 } | 531 } |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
915 DCHECK(result.get()); | 618 DCHECK(result.get()); |
916 | 619 |
917 result->second.path = second_path; | 620 result->second.path = second_path; |
918 result->second.error = error; | 621 result->second.error = error; |
919 result->second.proto = entry_proto.Pass(); | 622 result->second.proto = entry_proto.Pass(); |
920 | 623 |
921 callback.Run(result.Pass()); | 624 callback.Run(result.Pass()); |
922 } | 625 } |
923 | 626 |
924 } // namespace drive | 627 } // namespace drive |
OLD | NEW |