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

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

Issue 10827343: Split out gdata_directory_service* (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: rebase 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
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "chrome/browser/chromeos/gdata/gdata_directory_service.h"
6
7 #include <leveldb/db.h>
8
9 #include "base/message_loop_proxy.h"
10 #include "base/platform_file.h"
11 #include "base/string_number_conversions.h"
12 #include "base/string_util.h"
13 #include "base/stringprintf.h"
14 #include "base/sequenced_task_runner.h"
15 #include "base/tracked_objects.h"
16 #include "base/utf_string_conversions.h"
17 #include "chrome/browser/chromeos/gdata/gdata.pb.h"
18 #include "chrome/browser/chromeos/gdata/gdata_util.h"
19 #include "chrome/browser/chromeos/gdata/gdata_wapi_parser.h"
20 #include "content/public/browser/browser_thread.h"
21 #include "net/base/escape.h"
22
23 using content::BrowserThread;
24
25 namespace gdata {
26 namespace {
27
28 // m: prefix for filesystem metadata db keys, version and largest_changestamp.
29 // r: prefix for resource id db keys.
30 const char kDBKeyLargestChangestamp[] = "m:largest_changestamp";
31 const char kDBKeyVersion[] = "m:version";
32 const char kDBKeyResourceIdPrefix[] = "r:";
33
34 // Returns true if |proto| is a valid proto as the root directory.
35 // Used to reject incompatible proto.
36 bool IsValidRootDirectoryProto(const GDataDirectoryProto& proto) {
37 const GDataEntryProto& entry_proto = proto.gdata_entry();
38 // The title field for the root directory was originally empty, then
39 // changed to "gdata", then changed to "drive". Discard the proto data if
40 // the older formats are detected. See crbug.com/128133 for details.
41 if (entry_proto.title() != "drive") {
42 LOG(ERROR) << "Incompatible proto detected (bad title): "
43 << entry_proto.title();
44 return false;
45 }
46 // The title field for the root directory was originally empty. Discard
47 // the proto data if the older format is detected.
48 if (entry_proto.resource_id() != kGDataRootDirectoryResourceId) {
49 LOG(ERROR) << "Incompatible proto detected (bad resource ID): "
50 << entry_proto.resource_id();
51 return false;
52 }
53
54 return true;
55 }
56
57 } // namespace
58
59 EntryInfoResult::EntryInfoResult() : error(GDATA_FILE_ERROR_FAILED) {
60 }
61
62 EntryInfoResult::~EntryInfoResult() {
63 }
64
65 EntryInfoPairResult::EntryInfoPairResult() {
66 }
67
68 EntryInfoPairResult::~EntryInfoPairResult() {
69 }
70
71 // ResourceMetadataDB implementation.
72
73 // Params for GDatadirectoryServiceDB::Create.
74 struct CreateDBParams {
75 CreateDBParams(const FilePath& db_path,
76 base::SequencedTaskRunner* blocking_task_runner)
77 : db_path(db_path),
78 blocking_task_runner(blocking_task_runner) {
79 }
80
81 FilePath db_path;
82 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner;
83 scoped_ptr<ResourceMetadataDB> db;
84 GDataDirectoryService::SerializedMap serialized_resources;
85 };
86
87 // Wrapper for level db. All methods must be called on blocking thread.
88 class ResourceMetadataDB {
89 public:
90 ResourceMetadataDB(const FilePath& db_path,
91 base::SequencedTaskRunner* blocking_task_runner);
92
93 // Initializes the database.
94 void Init();
95
96 // Reads the database into |serialized_resources|.
97 void Read(GDataDirectoryService::SerializedMap* serialized_resources);
98
99 // Saves |serialized_resources| to the database.
100 void Save(const GDataDirectoryService::SerializedMap& serialized_resources);
101
102 private:
103 // Clears the database.
104 void Clear();
105
106 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
107 scoped_ptr<leveldb::DB> level_db_;
108 FilePath db_path_;
109 };
110
111 ResourceMetadataDB::ResourceMetadataDB(const FilePath& db_path,
112 base::SequencedTaskRunner* blocking_task_runner)
113 : blocking_task_runner_(blocking_task_runner),
114 db_path_(db_path) {
115 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread());
116 }
117
118 // Creates, initializes and reads from the database.
119 // This must be defined after ResourceMetadataDB and CreateDBParams.
120 static void CreateResourceMetadataDBOnBlockingPool(
121 CreateDBParams* params) {
122 DCHECK(params->blocking_task_runner->RunsTasksOnCurrentThread());
123 DCHECK(!params->db_path.empty());
124
125 params->db.reset(new ResourceMetadataDB(params->db_path,
126 params->blocking_task_runner));
127 params->db->Init();
128 params->db->Read(&params->serialized_resources);
129 }
130
131 void ResourceMetadataDB::Init() {
132 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread());
133 DCHECK(!db_path_.empty());
134
135 DVLOG(1) << "Init " << db_path_.value();
136
137 leveldb::DB* level_db = NULL;
138 leveldb::Options options;
139 options.create_if_missing = true;
140 leveldb::Status db_status = leveldb::DB::Open(options, db_path_.value(),
141 &level_db);
142 DCHECK(level_db);
143 DCHECK(db_status.ok());
144 level_db_.reset(level_db);
145 }
146
147 void ResourceMetadataDB::Read(
148 GDataDirectoryService::SerializedMap* serialized_resources) {
149 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread());
150 DCHECK(serialized_resources);
151 DVLOG(1) << "Read " << db_path_.value();
152
153 scoped_ptr<leveldb::Iterator> iter(level_db_->NewIterator(
154 leveldb::ReadOptions()));
155 for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
156 DVLOG(1) << "Read, resource " << iter->key().ToString();
157 serialized_resources->insert(std::make_pair(iter->key().ToString(),
158 iter->value().ToString()));
159 }
160 }
161
162 void ResourceMetadataDB::Save(
163 const GDataDirectoryService::SerializedMap& serialized_resources) {
164 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread());
165
166 Clear();
167 for (GDataDirectoryService::SerializedMap::const_iterator iter =
168 serialized_resources.begin();
169 iter != serialized_resources.end(); ++iter) {
170 DVLOG(1) << "Saving resource " << iter->first << " to db";
171 leveldb::Status status = level_db_->Put(leveldb::WriteOptions(),
172 leveldb::Slice(iter->first),
173 leveldb::Slice(iter->second));
174 if (!status.ok()) {
175 LOG(ERROR) << "leveldb Put failed of " << iter->first
176 << ", with " << status.ToString();
177 NOTREACHED();
178 }
179 }
180 }
181
182 void ResourceMetadataDB::Clear() {
183 level_db_.reset();
184 leveldb::DestroyDB(db_path_.value(), leveldb::Options());
185 Init();
186 }
187
188 // GDataDirectoryService class implementation.
189
190 GDataDirectoryService::GDataDirectoryService()
191 : blocking_task_runner_(NULL),
192 serialized_size_(0),
193 largest_changestamp_(0),
194 origin_(UNINITIALIZED),
195 weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
196 root_.reset(CreateGDataDirectory());
197 if (!util::IsDriveV2ApiEnabled())
198 InitializeRootEntry(kGDataRootDirectoryResourceId);
199 }
200
201 GDataDirectoryService::~GDataDirectoryService() {
202 ClearRoot();
203
204 // Ensure db is closed on the blocking pool.
205 if (blocking_task_runner_ && directory_service_db_.get())
206 blocking_task_runner_->DeleteSoon(FROM_HERE,
207 directory_service_db_.release());
208 }
209
210 GDataEntry* GDataDirectoryService::FromDocumentEntry(DocumentEntry* doc) {
211 DCHECK(doc);
212 GDataEntry* entry = NULL;
213 if (doc->is_folder())
214 entry = CreateGDataDirectory();
215 else if (doc->is_hosted_document() || doc->is_file())
216 entry = CreateGDataFile();
217
218 if (entry)
219 entry->InitFromDocumentEntry(doc);
220 return entry;
221 }
222
223 GDataFile* GDataDirectoryService::CreateGDataFile() {
224 return new GDataFile(this);
225 }
226
227 GDataDirectory* GDataDirectoryService::CreateGDataDirectory() {
228 return new GDataDirectory(this);
229 }
230
231 void GDataDirectoryService::InitializeRootEntry(const std::string& root_id) {
232 root_.reset(CreateGDataDirectory());
233 root_->set_title(kGDataRootDirectory);
234 root_->SetBaseNameFromTitle();
235 root_->set_resource_id(root_id);
236 AddEntryToResourceMap(root_.get());
237 }
238
239 void GDataDirectoryService::ClearRoot() {
240 // Note that children have a reference to root_,
241 // so we need to delete them here.
242 root_->RemoveChildren();
243 RemoveEntryFromResourceMap(root_.get());
244 DCHECK(resource_map_.empty());
245 resource_map_.clear();
246 root_.reset();
247 }
248
249 void GDataDirectoryService::AddEntryToDirectory(
250 GDataDirectory* directory,
251 GDataEntry* new_entry,
252 const FileMoveCallback& callback) {
253 DCHECK(directory);
254 DCHECK(new_entry);
255 DCHECK(!callback.is_null());
256
257 directory->AddEntry(new_entry);
258 DVLOG(1) << "AddEntryToDirectory " << new_entry->GetFilePath().value();
259 base::MessageLoopProxy::current()->PostTask(FROM_HERE,
260 base::Bind(callback, GDATA_FILE_OK, new_entry->GetFilePath()));
261 }
262
263 void GDataDirectoryService::MoveEntryToDirectory(
264 const FilePath& directory_path,
265 GDataEntry* entry,
266 const FileMoveCallback& callback) {
267 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
268 DCHECK(entry);
269 DCHECK(!callback.is_null());
270
271 if (entry->parent())
272 entry->parent()->RemoveChild(entry);
273
274 GDataEntry* destination = FindEntryByPathSync(directory_path);
275 FilePath moved_file_path;
276 GDataFileError error = GDATA_FILE_ERROR_FAILED;
277 if (!destination) {
278 error = GDATA_FILE_ERROR_NOT_FOUND;
279 } else if (!destination->AsGDataDirectory()) {
280 error = GDATA_FILE_ERROR_NOT_A_DIRECTORY;
281 } else {
282 destination->AsGDataDirectory()->AddEntry(entry);
283 moved_file_path = entry->GetFilePath();
284 error = GDATA_FILE_OK;
285 }
286 DVLOG(1) << "MoveEntryToDirectory " << moved_file_path.value();
287 base::MessageLoopProxy::current()->PostTask(
288 FROM_HERE, base::Bind(callback, error, moved_file_path));
289 }
290
291 void GDataDirectoryService::RemoveEntryFromParent(
292 GDataEntry* entry,
293 const FileMoveCallback& callback) {
294 GDataDirectory* parent = entry->parent();
295 DCHECK(parent);
296 DCHECK(!callback.is_null());
297 DVLOG(1) << "RemoveEntryFromParent " << entry->GetFilePath().value();
298
299 parent->RemoveEntry(entry);
300 base::MessageLoopProxy::current()->PostTask(FROM_HERE,
301 base::Bind(callback, GDATA_FILE_OK, parent->GetFilePath()));
302 }
303
304 void GDataDirectoryService::AddEntryToResourceMap(GDataEntry* entry) {
305 // GDataFileSystem has already locked.
306 DVLOG(1) << "AddEntryToResourceMap " << entry->resource_id();
307 resource_map_.insert(std::make_pair(entry->resource_id(), entry));
308 }
309
310 void GDataDirectoryService::RemoveEntryFromResourceMap(GDataEntry* entry) {
311 // GDataFileSystem has already locked.
312 resource_map_.erase(entry->resource_id());
313 }
314
315 GDataEntry* GDataDirectoryService::FindEntryByPathSync(
316 const FilePath& file_path) {
317 if (file_path == root_->GetFilePath())
318 return root_.get();
319
320 std::vector<FilePath::StringType> components;
321 file_path.GetComponents(&components);
322 GDataDirectory* current_dir = root_.get();
323
324 for (size_t i = 1; i < components.size() && current_dir; ++i) {
325 GDataEntry* entry = current_dir->FindChild(components[i]);
326 if (!entry)
327 return NULL;
328
329 if (i == components.size() - 1) // Last component.
330 return entry;
331 else
332 current_dir = entry->AsGDataDirectory();
333 }
334 return NULL;
335 }
336
337 void GDataDirectoryService::FindEntryByPathAndRunSync(
338 const FilePath& search_file_path,
339 const FindEntryCallback& callback) {
340 GDataEntry* entry = FindEntryByPathSync(search_file_path);
341 callback.Run(entry ? GDATA_FILE_OK : GDATA_FILE_ERROR_NOT_FOUND, entry);
342 }
343
344 GDataEntry* GDataDirectoryService::GetEntryByResourceId(
345 const std::string& resource) {
346 // GDataFileSystem has already locked.
347 ResourceMap::const_iterator iter = resource_map_.find(resource);
348 return iter == resource_map_.end() ? NULL : iter->second;
349 }
350
351 void GDataDirectoryService::GetEntryByResourceIdAsync(
352 const std::string& resource_id,
353 const GetEntryByResourceIdCallback& callback) {
354 GDataEntry* entry = GetEntryByResourceId(resource_id);
355 callback.Run(entry);
356 }
357
358 void GDataDirectoryService::GetEntryInfoByPath(
359 const FilePath& path,
360 const GetEntryInfoCallback& callback) {
361 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
362 DCHECK(!callback.is_null());
363
364 scoped_ptr<GDataEntryProto> entry_proto;
365 GDataFileError error = GDATA_FILE_ERROR_FAILED;
366
367 GDataEntry* entry = FindEntryByPathSync(path);
368 if (entry) {
369 entry_proto.reset(new GDataEntryProto);
370 entry->ToProtoFull(entry_proto.get());
371 error = GDATA_FILE_OK;
372 } else {
373 error = GDATA_FILE_ERROR_NOT_FOUND;
374 }
375
376 base::MessageLoopProxy::current()->PostTask(
377 FROM_HERE,
378 base::Bind(callback, error, base::Passed(&entry_proto)));
379 }
380
381 void GDataDirectoryService::ReadDirectoryByPath(
382 const FilePath& path,
383 const ReadDirectoryCallback& callback) {
384 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
385 DCHECK(!callback.is_null());
386
387 scoped_ptr<GDataEntryProtoVector> entries;
388 GDataFileError error = GDATA_FILE_ERROR_FAILED;
389
390 GDataEntry* entry = FindEntryByPathSync(path);
391 if (entry && entry->AsGDataDirectory()) {
392 entries = entry->AsGDataDirectory()->ToProtoVector();
393 error = GDATA_FILE_OK;
394 } else if (entry && !entry->AsGDataDirectory()) {
395 error = GDATA_FILE_ERROR_NOT_A_DIRECTORY;
396 } else {
397 error = GDATA_FILE_ERROR_NOT_FOUND;
398 }
399
400 base::MessageLoopProxy::current()->PostTask(
401 FROM_HERE,
402 base::Bind(callback, error, base::Passed(&entries)));
403 }
404
405 void GDataDirectoryService::GetEntryInfoPairByPaths(
406 const FilePath& first_path,
407 const FilePath& second_path,
408 const GetEntryInfoPairCallback& callback) {
409 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
410 DCHECK(!callback.is_null());
411
412 // Get the first entry.
413 GetEntryInfoByPath(
414 first_path,
415 base::Bind(&GDataDirectoryService::GetEntryInfoPairByPathsAfterGetFirst,
416 weak_ptr_factory_.GetWeakPtr(),
417 first_path,
418 second_path,
419 callback));
420 }
421
422 void GDataDirectoryService::RefreshFile(scoped_ptr<GDataFile> fresh_file) {
423 DCHECK(fresh_file.get());
424
425 // Need to get a reference here because Passed() could get evaluated first.
426 const std::string& resource_id = fresh_file->resource_id();
427 GetEntryByResourceIdAsync(
428 resource_id,
429 base::Bind(&GDataDirectoryService::RefreshFileInternal,
430 base::Passed(&fresh_file)));
431 }
432
433 // static
434 void GDataDirectoryService::RefreshFileInternal(
435 scoped_ptr<GDataFile> fresh_file,
436 GDataEntry* old_entry) {
437 GDataDirectory* entry_parent = old_entry ? old_entry->parent() : NULL;
438 if (entry_parent) {
439 DCHECK_EQ(fresh_file->resource_id(), old_entry->resource_id());
440 DCHECK(old_entry->AsGDataFile());
441
442 entry_parent->RemoveEntry(old_entry);
443 entry_parent->AddEntry(fresh_file.release());
444 }
445 }
446
447 void GDataDirectoryService::RefreshDirectory(
448 const std::string& directory_resource_id,
449 const ResourceMap& file_map,
450 const FileMoveCallback& callback) {
451 DCHECK(!callback.is_null());
452 GetEntryByResourceIdAsync(
453 directory_resource_id,
454 base::Bind(&GDataDirectoryService::RefreshDirectoryInternal,
455 file_map,
456 callback));
457 }
458
459 // static
460 void GDataDirectoryService::RefreshDirectoryInternal(
461 const ResourceMap& file_map,
462 const FileMoveCallback& callback,
463 GDataEntry* directory_entry) {
464 DCHECK(!callback.is_null());
465
466 if (!directory_entry) {
467 callback.Run(GDATA_FILE_ERROR_NOT_FOUND, FilePath());
468 return;
469 }
470
471 GDataDirectory* directory = directory_entry->AsGDataDirectory();
472 if (!directory) {
473 callback.Run(GDATA_FILE_ERROR_NOT_A_DIRECTORY, FilePath());
474 return;
475 }
476
477 directory->RemoveChildFiles();
478 // Add files from file_map.
479 for (ResourceMap::const_iterator it = file_map.begin();
480 it != file_map.end(); ++it) {
481 scoped_ptr<GDataEntry> entry(it->second);
482 // Skip if it's not a file (i.e. directory).
483 if (!entry->AsGDataFile())
484 continue;
485 directory->AddEntry(entry.release());
486 }
487
488 callback.Run(GDATA_FILE_OK, directory->GetFilePath());
489 }
490
491 void GDataDirectoryService::InitFromDB(
492 const FilePath& db_path,
493 base::SequencedTaskRunner* blocking_task_runner,
494 const FileOperationCallback& callback) {
495 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
496 DCHECK(!db_path.empty());
497 DCHECK(blocking_task_runner);
498
499 if (directory_service_db_.get()) {
500 if (!callback.is_null())
501 callback.Run(GDATA_FILE_ERROR_FAILED);
502 return;
503 }
504
505 blocking_task_runner_ = blocking_task_runner;
506
507 DVLOG(1) << "InitFromDB " << db_path.value();
508
509 CreateDBParams* create_params =
510 new CreateDBParams(db_path, blocking_task_runner);
511 blocking_task_runner_->PostTaskAndReply(
512 FROM_HERE,
513 base::Bind(&CreateResourceMetadataDBOnBlockingPool,
514 create_params),
515 base::Bind(&GDataDirectoryService::InitResourceMap,
516 weak_ptr_factory_.GetWeakPtr(),
517 base::Owned(create_params),
518 callback));
519 }
520
521 void GDataDirectoryService::InitResourceMap(
522 CreateDBParams* create_params,
523 const FileOperationCallback& callback) {
524 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
525 DCHECK(create_params);
526 DCHECK(!directory_service_db_.get());
527
528 SerializedMap* serialized_resources = &create_params->serialized_resources;
529 directory_service_db_ = create_params->db.Pass();
530 if (serialized_resources->empty()) {
531 origin_ = INITIALIZING;
532 if (!callback.is_null())
533 callback.Run(GDATA_FILE_ERROR_NOT_FOUND);
534 return;
535 }
536
537 ClearRoot();
538
539 // Version check.
540 int32 version = 0;
541 SerializedMap::iterator iter = serialized_resources->find(kDBKeyVersion);
542 if (iter == serialized_resources->end() ||
543 !base::StringToInt(iter->second, &version) ||
544 version != kProtoVersion) {
545 if (!callback.is_null())
546 callback.Run(GDATA_FILE_ERROR_FAILED);
547 return;
548 }
549 serialized_resources->erase(iter);
550
551 // Get the largest changestamp.
552 iter = serialized_resources->find(kDBKeyLargestChangestamp);
553 if (iter == serialized_resources->end() ||
554 !base::StringToInt64(iter->second, &largest_changestamp_)) {
555 NOTREACHED() << "Could not find/parse largest_changestamp";
556 if (!callback.is_null())
557 callback.Run(GDATA_FILE_ERROR_FAILED);
558 return;
559 } else {
560 DVLOG(1) << "InitResourceMap largest_changestamp_" << largest_changestamp_;
561 serialized_resources->erase(iter);
562 }
563
564 ResourceMap resource_map;
565 for (SerializedMap::const_iterator iter = serialized_resources->begin();
566 iter != serialized_resources->end(); ++iter) {
567 if (iter->first.find(kDBKeyResourceIdPrefix) != 0) {
568 NOTREACHED() << "Incorrect prefix for db key " << iter->first;
569 continue;
570 }
571
572 const std::string resource_id =
573 iter->first.substr(strlen(kDBKeyResourceIdPrefix));
574 scoped_ptr<GDataEntry> entry = FromProtoString(iter->second);
575 if (entry.get()) {
576 DVLOG(1) << "Inserting resource " << resource_id
577 << " into resource_map";
578 resource_map.insert(std::make_pair(resource_id, entry.release()));
579 } else {
580 NOTREACHED() << "Failed to parse GDataEntry for resource " << resource_id;
581 }
582 }
583
584 // Fix up parent-child relations.
585 for (ResourceMap::iterator iter = resource_map.begin();
586 iter != resource_map.end(); ++iter) {
587 GDataEntry* entry = iter->second;
588 ResourceMap::iterator parent_it =
589 resource_map.find(entry->parent_resource_id());
590 if (parent_it != resource_map.end()) {
591 GDataDirectory* parent = parent_it->second->AsGDataDirectory();
592 if (parent) {
593 DVLOG(1) << "Adding " << entry->resource_id()
594 << " as a child of " << parent->resource_id();
595 parent->AddEntry(entry);
596 } else {
597 NOTREACHED() << "Parent is not a directory " << parent->resource_id();
598 }
599 } else if (entry->resource_id() == kGDataRootDirectoryResourceId) {
600 root_.reset(entry->AsGDataDirectory());
601 DCHECK(root_.get());
602 AddEntryToResourceMap(root_.get());
603 } else {
604 NOTREACHED() << "Missing parent id " << entry->parent_resource_id()
605 << " for resource " << entry->resource_id();
606 }
607 }
608
609 DCHECK(root_.get());
610 DCHECK_EQ(resource_map.size(), resource_map_.size());
611 DCHECK_EQ(resource_map.size(), serialized_resources->size());
612
613 origin_ = FROM_CACHE;
614
615 if (!callback.is_null())
616 callback.Run(GDATA_FILE_OK);
617 }
618
619 void GDataDirectoryService::SaveToDB() {
620 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
621
622 if (!blocking_task_runner_ || !directory_service_db_.get()) {
623 NOTREACHED();
624 return;
625 }
626
627 size_t serialized_size = 0;
628 SerializedMap serialized_resources;
629 for (ResourceMap::const_iterator iter = resource_map_.begin();
630 iter != resource_map_.end(); ++iter) {
631 GDataEntryProto proto;
632 iter->second->ToProtoFull(&proto);
633 std::string serialized_string;
634 const bool ok = proto.SerializeToString(&serialized_string);
635 DCHECK(ok);
636 if (ok) {
637 serialized_resources.insert(
638 std::make_pair(std::string(kDBKeyResourceIdPrefix) + iter->first,
639 serialized_string));
640 serialized_size += serialized_string.size();
641 }
642 }
643
644 serialized_resources.insert(std::make_pair(kDBKeyVersion,
645 base::IntToString(kProtoVersion)));
646 serialized_resources.insert(std::make_pair(kDBKeyLargestChangestamp,
647 base::IntToString(largest_changestamp_)));
648 set_last_serialized(base::Time::Now());
649 set_serialized_size(serialized_size);
650
651 blocking_task_runner_->PostTask(
652 FROM_HERE,
653 base::Bind(&ResourceMetadataDB::Save,
654 base::Unretained(directory_service_db_.get()),
655 serialized_resources));
656 }
657
658 void GDataDirectoryService::SerializeToString(
659 std::string* serialized_proto) const {
660 GDataRootDirectoryProto proto;
661 root_->ToProto(proto.mutable_gdata_directory());
662 proto.set_largest_changestamp(largest_changestamp_);
663 proto.set_version(kProtoVersion);
664
665 const bool ok = proto.SerializeToString(serialized_proto);
666 DCHECK(ok);
667 }
668
669 bool GDataDirectoryService::ParseFromString(
670 const std::string& serialized_proto) {
671 GDataRootDirectoryProto proto;
672 if (!proto.ParseFromString(serialized_proto))
673 return false;
674
675 if (proto.version() != kProtoVersion) {
676 LOG(ERROR) << "Incompatible proto detected (incompatible version): "
677 << proto.version();
678 return false;
679 }
680
681 if (!IsValidRootDirectoryProto(proto.gdata_directory()))
682 return false;
683
684 if (!root_->FromProto(proto.gdata_directory()))
685 return false;
686
687 origin_ = FROM_CACHE;
688 largest_changestamp_ = proto.largest_changestamp();
689
690 return true;
691 }
692
693 scoped_ptr<GDataEntry> GDataDirectoryService::FromProtoString(
694 const std::string& serialized_proto) {
695 GDataEntryProto entry_proto;
696 if (!entry_proto.ParseFromString(serialized_proto))
697 return scoped_ptr<GDataEntry>();
698
699 scoped_ptr<GDataEntry> entry;
700 if (entry_proto.file_info().is_directory()) {
701 entry.reset(CreateGDataDirectory());
702 // Call GDataEntry::FromProto instead of GDataDirectory::FromProto because
703 // the proto does not include children.
704 if (!entry->FromProto(entry_proto)) {
705 NOTREACHED() << "FromProto (directory) failed";
706 entry.reset();
707 }
708 } else {
709 scoped_ptr<GDataFile> file(CreateGDataFile());
710 // Call GDataFile::FromProto.
711 if (file->FromProto(entry_proto)) {
712 entry.reset(file.release());
713 } else {
714 NOTREACHED() << "FromProto (file) failed";
715 }
716 }
717 return entry.Pass();
718 }
719
720 void GDataDirectoryService::GetEntryInfoPairByPathsAfterGetFirst(
721 const FilePath& first_path,
722 const FilePath& second_path,
723 const GetEntryInfoPairCallback& callback,
724 GDataFileError error,
725 scoped_ptr<GDataEntryProto> entry_proto) {
726 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
727 DCHECK(!callback.is_null());
728
729 scoped_ptr<EntryInfoPairResult> result(new EntryInfoPairResult);
730 result->first.path = first_path;
731 result->first.error = error;
732 result->first.proto = entry_proto.Pass();
733
734 // If the first one is not found, don't continue.
735 if (error != GDATA_FILE_OK) {
736 callback.Run(result.Pass());
737 return;
738 }
739
740 // Get the second entry.
741 GetEntryInfoByPath(
742 second_path,
743 base::Bind(&GDataDirectoryService::GetEntryInfoPairByPathsAfterGetSecond,
744 weak_ptr_factory_.GetWeakPtr(),
745 second_path,
746 callback,
747 base::Passed(&result)));
748 }
749
750 void GDataDirectoryService::GetEntryInfoPairByPathsAfterGetSecond(
751 const FilePath& second_path,
752 const GetEntryInfoPairCallback& callback,
753 scoped_ptr<EntryInfoPairResult> result,
754 GDataFileError error,
755 scoped_ptr<GDataEntryProto> entry_proto) {
756 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
757 DCHECK(!callback.is_null());
758 DCHECK(result.get());
759
760 result->second.path = second_path;
761 result->second.error = error;
762 result->second.proto = entry_proto.Pass();
763
764 callback.Run(result.Pass());
765 }
766
767 } // namespace gdata
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698