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

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

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

Powered by Google App Engine
This is Rietveld 408576698