OLD | NEW |
| (Empty) |
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_ut
il.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 = 0; // 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 disabled_origins_.erase(found); | |
586 | |
587 // |origin| goes back to DriveFileSyncService::pending_batch_sync_origins_ | |
588 // only and is not stored in drive_metadata_store. | |
589 found = incremental_sync_origins_.find(origin); | |
590 if (found != incremental_sync_origins_.end()) | |
591 incremental_sync_origins_.erase(found); | |
592 | |
593 scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch); | |
594 batch->Delete(CreateKeyForOriginRoot(origin, INCREMENTAL_SYNC_ORIGIN)); | |
595 batch->Delete(CreateKeyForOriginRoot(origin, DISABLED_ORIGIN)); | |
596 WriteToDB(batch.Pass(), callback); | |
597 } | |
598 | |
599 void DriveMetadataStore::DisableOrigin( | |
600 const GURL& origin, | |
601 const SyncStatusCallback& callback) { | |
602 DCHECK(CalledOnValidThread()); | |
603 | |
604 std::string resource_id; | |
605 if (!EraseIfExists(&incremental_sync_origins_, origin, &resource_id)) | |
606 return; | |
607 disabled_origins_[origin] = resource_id; | |
608 | |
609 scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch); | |
610 batch->Delete(CreateKeyForOriginRoot(origin, INCREMENTAL_SYNC_ORIGIN)); | |
611 batch->Put(CreateKeyForOriginRoot(origin, DISABLED_ORIGIN), | |
612 drive_backend::RemoveWapiIdPrefix(resource_id)); | |
613 AppendMetadataDeletionToBatch(metadata_map_, origin, batch.get()); | |
614 metadata_map_.erase(origin); | |
615 | |
616 WriteToDB(batch.Pass(), callback); | |
617 } | |
618 | |
619 void DriveMetadataStore::RemoveOrigin( | |
620 const GURL& origin, | |
621 const SyncStatusCallback& callback) { | |
622 DCHECK(CalledOnValidThread()); | |
623 | |
624 std::string resource_id; | |
625 if (!EraseIfExists(&incremental_sync_origins_, origin, &resource_id) && | |
626 !EraseIfExists(&disabled_origins_, origin, &resource_id)) | |
627 return; | |
628 origin_by_resource_id_.erase(resource_id); | |
629 | |
630 scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch); | |
631 batch->Delete(CreateKeyForOriginRoot(origin, INCREMENTAL_SYNC_ORIGIN)); | |
632 batch->Delete(CreateKeyForOriginRoot(origin, DISABLED_ORIGIN)); | |
633 AppendMetadataDeletionToBatch(metadata_map_, origin, batch.get()); | |
634 metadata_map_.erase(origin); | |
635 | |
636 WriteToDB(batch.Pass(), callback); | |
637 } | |
638 | |
639 void DriveMetadataStore::DidUpdateOrigin( | |
640 const SyncStatusCallback& callback, | |
641 SyncStatusCode status) { | |
642 UpdateDBStatus(status); | |
643 callback.Run(status); | |
644 } | |
645 | |
646 void DriveMetadataStore::WriteToDB(scoped_ptr<leveldb::WriteBatch> batch, | |
647 const SyncStatusCallback& callback) { | |
648 base::PostTaskAndReplyWithResult( | |
649 file_task_runner_.get(), | |
650 FROM_HERE, | |
651 base::Bind(&leveldb::DB::Write, | |
652 base::Unretained(db_.get()), | |
653 leveldb::WriteOptions(), | |
654 base::Owned(batch.release())), | |
655 base::Bind(&DriveMetadataStore::UpdateDBStatusAndInvokeCallback, | |
656 AsWeakPtr(), | |
657 callback)); | |
658 } | |
659 | |
660 void DriveMetadataStore::UpdateDBStatus(SyncStatusCode status) { | |
661 DCHECK(CalledOnValidThread()); | |
662 if (db_status_ != SYNC_STATUS_OK && | |
663 db_status_ != SYNC_DATABASE_ERROR_NOT_FOUND) { | |
664 // TODO(tzik): Handle database corruption. http://crbug.com/153709 | |
665 db_status_ = status; | |
666 util::Log(logging::LOG_WARNING, | |
667 FROM_HERE, | |
668 "DriveMetadataStore turned to wrong state: %s", | |
669 SyncStatusCodeToString(status)); | |
670 return; | |
671 } | |
672 db_status_ = SYNC_STATUS_OK; | |
673 } | |
674 | |
675 void DriveMetadataStore::UpdateDBStatusAndInvokeCallback( | |
676 const SyncStatusCallback& callback, | |
677 const leveldb::Status& leveldb_status) { | |
678 SyncStatusCode status = LevelDBStatusToSyncStatusCode(leveldb_status); | |
679 UpdateDBStatus(status); | |
680 callback.Run(status); | |
681 } | |
682 | |
683 SyncStatusCode DriveMetadataStore::GetConflictURLs( | |
684 fileapi::FileSystemURLSet* urls) const { | |
685 DCHECK(CalledOnValidThread()); | |
686 DCHECK_EQ(SYNC_STATUS_OK, db_status_); | |
687 | |
688 urls->clear(); | |
689 for (MetadataMap::const_iterator origin_itr = metadata_map_.begin(); | |
690 origin_itr != metadata_map_.end(); | |
691 ++origin_itr) { | |
692 for (PathToMetadata::const_iterator itr = origin_itr->second.begin(); | |
693 itr != origin_itr->second.end(); | |
694 ++itr) { | |
695 if (itr->second.conflicted()) { | |
696 urls->insert(CreateSyncableFileSystemURL( | |
697 origin_itr->first, itr->first)); | |
698 } | |
699 } | |
700 } | |
701 return SYNC_STATUS_OK; | |
702 } | |
703 | |
704 SyncStatusCode DriveMetadataStore::GetToBeFetchedFiles( | |
705 URLAndDriveMetadataList* list) const { | |
706 DCHECK(CalledOnValidThread()); | |
707 DCHECK_EQ(SYNC_STATUS_OK, db_status_); | |
708 | |
709 list->clear(); | |
710 for (MetadataMap::const_iterator origin_itr = metadata_map_.begin(); | |
711 origin_itr != metadata_map_.end(); | |
712 ++origin_itr) { | |
713 for (PathToMetadata::const_iterator itr = origin_itr->second.begin(); | |
714 itr != origin_itr->second.end(); | |
715 ++itr) { | |
716 if (itr->second.to_be_fetched()) { | |
717 FileSystemURL url = CreateSyncableFileSystemURL( | |
718 origin_itr->first, itr->first); | |
719 list->push_back(std::make_pair(url, itr->second)); | |
720 } | |
721 } | |
722 } | |
723 return SYNC_STATUS_OK; | |
724 } | |
725 | |
726 std::string DriveMetadataStore::GetResourceIdForOrigin( | |
727 const GURL& origin) const { | |
728 DCHECK(CalledOnValidThread()); | |
729 | |
730 // If we don't have valid root directory (this could be reset even after | |
731 // initialized) just return empty string, as the origin directories | |
732 // in the root directory must have become invalid now too. | |
733 if (sync_root_directory().empty()) | |
734 return std::string(); | |
735 | |
736 ResourceIdByOrigin::const_iterator found = | |
737 incremental_sync_origins_.find(origin); | |
738 if (found != incremental_sync_origins_.end()) | |
739 return found->second; | |
740 | |
741 found = disabled_origins_.find(origin); | |
742 if (found != disabled_origins_.end()) | |
743 return found->second; | |
744 | |
745 return std::string(); | |
746 } | |
747 | |
748 void DriveMetadataStore::GetAllOrigins(std::vector<GURL>* origins) { | |
749 DCHECK(CalledOnValidThread()); | |
750 DCHECK(origins); | |
751 origins->clear(); | |
752 origins->reserve(incremental_sync_origins_.size() + | |
753 disabled_origins_.size()); | |
754 AddOriginsToVector(origins, incremental_sync_origins_); | |
755 AddOriginsToVector(origins, disabled_origins_); | |
756 } | |
757 | |
758 bool DriveMetadataStore::GetOriginByOriginRootDirectoryId( | |
759 const std::string& resource_id, | |
760 GURL* origin) { | |
761 DCHECK(CalledOnValidThread()); | |
762 DCHECK(origin); | |
763 | |
764 OriginByResourceId::iterator found = origin_by_resource_id_.find(resource_id); | |
765 if (found == origin_by_resource_id_.end()) | |
766 return false; | |
767 *origin = found->second; | |
768 return true; | |
769 } | |
770 | |
771 scoped_ptr<base::ListValue> DriveMetadataStore::DumpFiles(const GURL& origin) { | |
772 DCHECK(CalledOnValidThread()); | |
773 | |
774 scoped_ptr<base::ListValue> files(new base::ListValue); | |
775 | |
776 MetadataMap::const_iterator found = metadata_map_.find(origin); | |
777 if (found == metadata_map_.end()) | |
778 return make_scoped_ptr(new base::ListValue); | |
779 | |
780 for (PathToMetadata::const_iterator itr = found->second.begin(); | |
781 itr != found->second.end(); | |
782 ++itr) { | |
783 // Convert Drive specific metadata to Common File metadata object. | |
784 const DriveMetadata& metadata = itr->second; | |
785 | |
786 base::DictionaryValue* file = new DictionaryValue; | |
787 file->SetString("path", itr->first.AsUTF8Unsafe()); | |
788 file->SetString("title", itr->first.BaseName().AsUTF8Unsafe()); | |
789 file->SetString("type", DriveTypeToString(metadata.type())); | |
790 | |
791 base::DictionaryValue* details = new DictionaryValue; | |
792 details->SetString("resource_id", metadata.resource_id()); | |
793 details->SetString("md5", metadata.md5_checksum()); | |
794 details->SetString("dirty", metadata.to_be_fetched() ? "true" : "false"); | |
795 | |
796 file->Set("details", details); | |
797 files->Append(file); | |
798 } | |
799 | |
800 return files.Pass(); | |
801 } | |
802 | |
803 } // namespace sync_file_system | |
OLD | NEW |