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

Side by Side Diff: chrome/browser/sync_file_system/drive_backend/conflict_resolver.cc

Issue 302003013: [SyncFS] Run V2 backend tasks as SyncTask (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 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 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/sync_file_system/drive_backend/conflict_resolver.h" 5 #include "chrome/browser/sync_file_system/drive_backend/conflict_resolver.h"
6 6
7 #include "base/callback.h" 7 #include "base/callback.h"
8 #include "base/format_macros.h" 8 #include "base/format_macros.h"
9 #include "base/location.h" 9 #include "base/location.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "base/strings/stringprintf.h"
11 #include "chrome/browser/drive/drive_api_util.h" 12 #include "chrome/browser/drive/drive_api_util.h"
12 #include "chrome/browser/drive/drive_service_interface.h" 13 #include "chrome/browser/drive/drive_service_interface.h"
13 #include "chrome/browser/drive/drive_uploader.h" 14 #include "chrome/browser/drive/drive_uploader.h"
14 #include "chrome/browser/sync_file_system/drive_backend/drive_backend_util.h" 15 #include "chrome/browser/sync_file_system/drive_backend/drive_backend_util.h"
15 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.h" 16 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.h"
16 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.pb.h" 17 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.pb.h"
17 #include "chrome/browser/sync_file_system/drive_backend/sync_engine_context.h" 18 #include "chrome/browser/sync_file_system/drive_backend/sync_engine_context.h"
19 #include "chrome/browser/sync_file_system/drive_backend/sync_task_manager.h"
20 #include "chrome/browser/sync_file_system/drive_backend/sync_task_token.h"
18 #include "chrome/browser/sync_file_system/logger.h" 21 #include "chrome/browser/sync_file_system/logger.h"
19 #include "google_apis/drive/drive_api_parser.h" 22 #include "google_apis/drive/drive_api_parser.h"
20 23
21 namespace sync_file_system { 24 namespace sync_file_system {
22 namespace drive_backend { 25 namespace drive_backend {
23 26
24 ConflictResolver::ConflictResolver(SyncEngineContext* sync_context) 27 ConflictResolver::ConflictResolver(SyncEngineContext* sync_context)
25 : sync_context_(sync_context), 28 : sync_context_(sync_context),
26 weak_ptr_factory_(this) {} 29 weak_ptr_factory_(this) {}
27 30
28 ConflictResolver::~ConflictResolver() {} 31 ConflictResolver::~ConflictResolver() {}
29 32
30 void ConflictResolver::RunExclusive(const SyncStatusCallback& callback) { 33 void ConflictResolver::RunPreflight(scoped_ptr<SyncTaskToken> token) {
34 token->InitializeTaskLog("Conflict Resolution");
35
36 scoped_ptr<BlockingFactor> blocking_factor(new BlockingFactor);
37 blocking_factor->exclusive = true;
38 SyncTaskManager::UpdateBlockingFactor(
39 token.Pass(), blocking_factor.Pass(),
40 base::Bind(&ConflictResolver::RunExclusive,
41 weak_ptr_factory_.GetWeakPtr()));
42 }
43
44 void ConflictResolver::RunExclusive(scoped_ptr<SyncTaskToken> token) {
31 if (!IsContextReady()) { 45 if (!IsContextReady()) {
32 NOTREACHED(); 46 NOTREACHED();
33 callback.Run(SYNC_STATUS_FAILED); 47 SyncTaskManager::NotifyTaskDone(token.Pass(), SYNC_STATUS_FAILED);
34 return; 48 return;
35 } 49 }
36 50
37 // Conflict resolution should be invoked on clean tree. 51 // Conflict resolution should be invoked on clean tree.
38 if (metadata_database()->HasDirtyTracker()) { 52 if (metadata_database()->HasDirtyTracker()) {
39 NOTREACHED(); 53 NOTREACHED();
40 callback.Run(SYNC_STATUS_FAILED); 54 SyncTaskManager::NotifyTaskDone(token.Pass(), SYNC_STATUS_FAILED);
41 return; 55 return;
42 } 56 }
43 57
44 TrackerIDSet trackers; 58 TrackerIDSet trackers;
45 if (metadata_database()->GetMultiParentFileTrackers( 59 if (metadata_database()->GetMultiParentFileTrackers(
46 &target_file_id_, &trackers)) { 60 &target_file_id_, &trackers)) {
47 DCHECK_LT(1u, trackers.size()); 61 DCHECK_LT(1u, trackers.size());
48 if (!trackers.has_active()) { 62 if (!trackers.has_active()) {
49 NOTREACHED(); 63 NOTREACHED();
50 callback.Run(SYNC_STATUS_FAILED); 64 SyncTaskManager::NotifyTaskDone(token.Pass(), SYNC_STATUS_FAILED);
51 return; 65 return;
52 } 66 }
53 67
54 util::Log(logging::LOG_VERBOSE, FROM_HERE, 68 token->RecordLog(base::StringPrintf(
55 "[ConflictResolver] Detected multi-parent trackers " 69 "Detected multi-parent trackers (active tracker_id=%" PRId64 ")",
56 "(active tracker_id=%" PRId64 ")", 70 trackers.active_tracker()));
57 trackers.active_tracker());
58 71
59 DCHECK(trackers.has_active()); 72 DCHECK(trackers.has_active());
60 for (TrackerIDSet::const_iterator itr = trackers.begin(); 73 for (TrackerIDSet::const_iterator itr = trackers.begin();
61 itr != trackers.end(); ++itr) { 74 itr != trackers.end(); ++itr) {
62 FileTracker tracker; 75 FileTracker tracker;
63 if (!metadata_database()->FindTrackerByTrackerID(*itr, &tracker)) { 76 if (!metadata_database()->FindTrackerByTrackerID(*itr, &tracker)) {
64 NOTREACHED(); 77 NOTREACHED();
65 continue; 78 continue;
66 } 79 }
67 80
68 if (tracker.active()) 81 if (tracker.active())
69 continue; 82 continue;
70 83
71 FileTracker parent_tracker; 84 FileTracker parent_tracker;
72 bool should_success = metadata_database()->FindTrackerByTrackerID( 85 bool should_success = metadata_database()->FindTrackerByTrackerID(
73 tracker.parent_tracker_id(), &parent_tracker); 86 tracker.parent_tracker_id(), &parent_tracker);
74 if (!should_success) { 87 if (!should_success) {
75 NOTREACHED(); 88 NOTREACHED();
76 callback.Run(SYNC_STATUS_FAILED); 89 SyncTaskManager::NotifyTaskDone(token.Pass(), SYNC_STATUS_FAILED);
77 return; 90 return;
78 } 91 }
79 parents_to_remove_.push_back(parent_tracker.file_id()); 92 parents_to_remove_.push_back(parent_tracker.file_id());
80 } 93 }
81 DetachFromNonPrimaryParents(callback); 94 DetachFromNonPrimaryParents(token.Pass());
82 return; 95 return;
83 } 96 }
84 97
85 if (metadata_database()->GetConflictingTrackers(&trackers)) { 98 if (metadata_database()->GetConflictingTrackers(&trackers)) {
86 target_file_id_ = PickPrimaryFile(trackers); 99 target_file_id_ = PickPrimaryFile(trackers);
87 DCHECK(!target_file_id_.empty()); 100 DCHECK(!target_file_id_.empty());
88 int64 primary_tracker_id = -1; 101 int64 primary_tracker_id = -1;
89 for (TrackerIDSet::const_iterator itr = trackers.begin(); 102 for (TrackerIDSet::const_iterator itr = trackers.begin();
90 itr != trackers.end(); ++itr) { 103 itr != trackers.end(); ++itr) {
91 FileTracker tracker; 104 FileTracker tracker;
92 if (!metadata_database()->FindTrackerByTrackerID(*itr, &tracker)) { 105 if (!metadata_database()->FindTrackerByTrackerID(*itr, &tracker)) {
93 NOTREACHED(); 106 NOTREACHED();
94 continue; 107 continue;
95 } 108 }
96 if (tracker.file_id() != target_file_id_) { 109 if (tracker.file_id() != target_file_id_) {
97 non_primary_file_ids_.push_back( 110 non_primary_file_ids_.push_back(
98 std::make_pair(tracker.file_id(), tracker.synced_details().etag())); 111 std::make_pair(tracker.file_id(), tracker.synced_details().etag()));
99 } else { 112 } else {
100 primary_tracker_id = tracker.tracker_id(); 113 primary_tracker_id = tracker.tracker_id();
101 } 114 }
102 } 115 }
103 116
104 util::Log(logging::LOG_VERBOSE, FROM_HERE, 117 token->RecordLog(base::StringPrintf(
105 "[ConflictResolver] Detected %" PRIuS " conflicting trackers " 118 "Detected %" PRIuS " conflicting trackers "
106 "(primary tracker_id=%" PRId64 ")", 119 "(primary tracker_id=%" PRId64 ")",
107 non_primary_file_ids_.size(), primary_tracker_id); 120 non_primary_file_ids_.size(), primary_tracker_id));
108 121
109 RemoveNonPrimaryFiles(callback); 122 RemoveNonPrimaryFiles(token.Pass());
110 return; 123 return;
111 } 124 }
112 125
113 callback.Run(SYNC_STATUS_NO_CONFLICT); 126 SyncTaskManager::NotifyTaskDone(token.Pass(), SYNC_STATUS_NO_CONFLICT);
114 } 127 }
115 128
116 void ConflictResolver::DetachFromNonPrimaryParents( 129 void ConflictResolver::DetachFromNonPrimaryParents(
117 const SyncStatusCallback& callback) { 130 scoped_ptr<SyncTaskToken> token) {
118 DCHECK(!parents_to_remove_.empty()); 131 DCHECK(!parents_to_remove_.empty());
119 132
120 // TODO(tzik): Check if ETag match is available for 133 // TODO(tzik): Check if ETag match is available for
121 // RemoteResourceFromDirectory. 134 // RemoteResourceFromDirectory.
122 std::string parent_folder_id = parents_to_remove_.back(); 135 std::string parent_folder_id = parents_to_remove_.back();
123 parents_to_remove_.pop_back(); 136 parents_to_remove_.pop_back();
137
138 token->RecordLog(base::StringPrintf(
139 "Detach %s from %s",
140 target_file_id_.c_str(), parent_folder_id.c_str()));
141
124 drive_service()->RemoveResourceFromDirectory( 142 drive_service()->RemoveResourceFromDirectory(
125 parent_folder_id, target_file_id_, 143 parent_folder_id, target_file_id_,
126 base::Bind(&ConflictResolver::DidDetachFromParent, 144 base::Bind(&ConflictResolver::DidDetachFromParent,
127 weak_ptr_factory_.GetWeakPtr(), 145 weak_ptr_factory_.GetWeakPtr(),
128 callback)); 146 base::Passed(&token)));
129 util::Log(logging::LOG_VERBOSE, FROM_HERE,
130 "[ConflictResolver] Detach %s from %s",
131 target_file_id_.c_str(), parent_folder_id.c_str());
132 } 147 }
133 148
134 void ConflictResolver::DidDetachFromParent(const SyncStatusCallback& callback, 149 void ConflictResolver::DidDetachFromParent(scoped_ptr<SyncTaskToken> token,
135 google_apis::GDataErrorCode error) { 150 google_apis::GDataErrorCode error) {
136 SyncStatusCode status = GDataErrorCodeToSyncStatusCode(error); 151 SyncStatusCode status = GDataErrorCodeToSyncStatusCode(error);
137 if (status != SYNC_STATUS_OK) { 152 if (status != SYNC_STATUS_OK) {
138 callback.Run(status); 153 SyncTaskManager::NotifyTaskDone(token.Pass(), status);
139 return; 154 return;
140 } 155 }
141 156
142 if (!parents_to_remove_.empty()) { 157 if (!parents_to_remove_.empty()) {
143 DetachFromNonPrimaryParents(callback); 158 DetachFromNonPrimaryParents(token.Pass());
144 return; 159 return;
145 } 160 }
146 161
147 callback.Run(SYNC_STATUS_OK); 162 SyncTaskManager::NotifyTaskDone(token.Pass(), SYNC_STATUS_OK);
148 } 163 }
149 164
150 std::string ConflictResolver::PickPrimaryFile(const TrackerIDSet& trackers) { 165 std::string ConflictResolver::PickPrimaryFile(const TrackerIDSet& trackers) {
151 scoped_ptr<FileMetadata> primary; 166 scoped_ptr<FileMetadata> primary;
152 for (TrackerIDSet::const_iterator itr = trackers.begin(); 167 for (TrackerIDSet::const_iterator itr = trackers.begin();
153 itr != trackers.end(); ++itr) { 168 itr != trackers.end(); ++itr) {
154 FileTracker tracker; 169 FileTracker tracker;
155 if (!metadata_database()->FindTrackerByTrackerID(*itr, &tracker)) { 170 if (!metadata_database()->FindTrackerByTrackerID(*itr, &tracker)) {
156 NOTREACHED(); 171 NOTREACHED();
157 continue; 172 continue;
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
205 primary = file_metadata.Pass(); 220 primary = file_metadata.Pass();
206 continue; 221 continue;
207 } 222 }
208 } 223 }
209 224
210 if (primary) 225 if (primary)
211 return primary->file_id(); 226 return primary->file_id();
212 return std::string(); 227 return std::string();
213 } 228 }
214 229
215 void ConflictResolver::RemoveNonPrimaryFiles( 230 void ConflictResolver::RemoveNonPrimaryFiles(scoped_ptr<SyncTaskToken> token) {
216 const SyncStatusCallback& callback) {
217 DCHECK(!non_primary_file_ids_.empty()); 231 DCHECK(!non_primary_file_ids_.empty());
218 232
219 std::string file_id = non_primary_file_ids_.back().first; 233 std::string file_id = non_primary_file_ids_.back().first;
220 std::string etag = non_primary_file_ids_.back().second; 234 std::string etag = non_primary_file_ids_.back().second;
221 non_primary_file_ids_.pop_back(); 235 non_primary_file_ids_.pop_back();
222 236
223 DCHECK_NE(target_file_id_, file_id); 237 DCHECK_NE(target_file_id_, file_id);
224 238
225 util::Log(logging::LOG_VERBOSE, FROM_HERE, 239 token->RecordLog(base::StringPrintf(
226 "[ConflictResolver] Remove non-primary file %s", file_id.c_str()); 240 "Remove non-primary file %s", file_id.c_str()));
227 241
228 // TODO(tzik): Check if the file is a folder, and merge its contents into 242 // TODO(tzik): Check if the file is a folder, and merge its contents into
229 // the folder identified by |target_file_id_|. 243 // the folder identified by |target_file_id_|.
230 drive_service()->DeleteResource( 244 drive_service()->DeleteResource(
231 file_id, etag, 245 file_id, etag,
232 base::Bind(&ConflictResolver::DidRemoveFile, 246 base::Bind(&ConflictResolver::DidRemoveFile,
233 weak_ptr_factory_.GetWeakPtr(), 247 weak_ptr_factory_.GetWeakPtr(),
234 callback, file_id)); 248 base::Passed(&token), file_id));
235 } 249 }
236 250
237 void ConflictResolver::DidRemoveFile(const SyncStatusCallback& callback, 251 void ConflictResolver::DidRemoveFile(scoped_ptr<SyncTaskToken> token,
238 const std::string& file_id, 252 const std::string& file_id,
239 google_apis::GDataErrorCode error) { 253 google_apis::GDataErrorCode error) {
240 if (error == google_apis::HTTP_PRECONDITION || 254 if (error == google_apis::HTTP_PRECONDITION ||
241 error == google_apis::HTTP_CONFLICT) { 255 error == google_apis::HTTP_CONFLICT) {
242 UpdateFileMetadata(file_id, callback); 256 UpdateFileMetadata(file_id, token.Pass());
243 return; 257 return;
244 } 258 }
245 259
246 SyncStatusCode status = GDataErrorCodeToSyncStatusCode(error); 260 SyncStatusCode status = GDataErrorCodeToSyncStatusCode(error);
247 if (status != SYNC_STATUS_OK && error != google_apis::HTTP_NOT_FOUND) { 261 if (status != SYNC_STATUS_OK && error != google_apis::HTTP_NOT_FOUND) {
248 callback.Run(status); 262 SyncTaskManager::NotifyTaskDone(token.Pass(), status);
249 return; 263 return;
250 } 264 }
251 265
252 deleted_file_ids_.push_back(file_id); 266 deleted_file_ids_.push_back(file_id);
253 if (!non_primary_file_ids_.empty()) { 267 if (!non_primary_file_ids_.empty()) {
254 RemoveNonPrimaryFiles(callback); 268 RemoveNonPrimaryFiles(token.Pass());
255 return; 269 return;
256 } 270 }
257 271
258 metadata_database()->UpdateByDeletedRemoteFileList( 272 metadata_database()->UpdateByDeletedRemoteFileList(
259 deleted_file_ids_, callback); 273 deleted_file_ids_, SyncTaskToken::WrapToCallback(token.Pass()));
260 } 274 }
261 275
262 bool ConflictResolver::IsContextReady() { 276 bool ConflictResolver::IsContextReady() {
263 return sync_context_->GetDriveService() && 277 return sync_context_->GetDriveService() &&
264 sync_context_->GetMetadataDatabase(); 278 sync_context_->GetMetadataDatabase();
265 } 279 }
266 280
267 void ConflictResolver::UpdateFileMetadata( 281 void ConflictResolver::UpdateFileMetadata(
268 const std::string& file_id, 282 const std::string& file_id,
269 const SyncStatusCallback& callback) { 283 scoped_ptr<SyncTaskToken> token) {
270 drive_service()->GetFileResource( 284 drive_service()->GetFileResource(
271 file_id, 285 file_id,
272 base::Bind(&ConflictResolver::DidGetRemoteMetadata, 286 base::Bind(&ConflictResolver::DidGetRemoteMetadata,
273 weak_ptr_factory_.GetWeakPtr(), file_id, callback)); 287 weak_ptr_factory_.GetWeakPtr(), file_id,
288 base::Passed(&token)));
274 } 289 }
275 290
276 void ConflictResolver::DidGetRemoteMetadata( 291 void ConflictResolver::DidGetRemoteMetadata(
277 const std::string& file_id, 292 const std::string& file_id,
278 const SyncStatusCallback& callback, 293 scoped_ptr<SyncTaskToken> token,
279 google_apis::GDataErrorCode error, 294 google_apis::GDataErrorCode error,
280 scoped_ptr<google_apis::FileResource> entry) { 295 scoped_ptr<google_apis::FileResource> entry) {
281 SyncStatusCode status = GDataErrorCodeToSyncStatusCode(error); 296 SyncStatusCode status = GDataErrorCodeToSyncStatusCode(error);
282 if (status != SYNC_STATUS_OK && error != google_apis::HTTP_NOT_FOUND) { 297 if (status != SYNC_STATUS_OK && error != google_apis::HTTP_NOT_FOUND) {
283 callback.Run(status); 298 SyncTaskManager::NotifyTaskDone(token.Pass(), status);
284 return; 299 return;
285 } 300 }
286 301
287 if (error != google_apis::HTTP_NOT_FOUND) { 302 if (error != google_apis::HTTP_NOT_FOUND) {
288 metadata_database()->UpdateByDeletedRemoteFile(file_id, callback); 303 metadata_database()->UpdateByDeletedRemoteFile(
304 file_id, SyncTaskToken::WrapToCallback(token.Pass()));
289 return; 305 return;
290 } 306 }
291 307
292 if (!entry) { 308 if (!entry) {
293 NOTREACHED(); 309 NOTREACHED();
294 callback.Run(SYNC_STATUS_FAILED); 310 SyncTaskManager::NotifyTaskDone(token.Pass(), SYNC_STATUS_FAILED);
295 return; 311 return;
296 } 312 }
297 313
298 metadata_database()->UpdateByFileResource(*entry, callback); 314 metadata_database()->UpdateByFileResource(
315 *entry, SyncTaskToken::WrapToCallback(token.Pass()));
299 } 316 }
300 317
301 drive::DriveServiceInterface* ConflictResolver::drive_service() { 318 drive::DriveServiceInterface* ConflictResolver::drive_service() {
302 set_used_network(true); 319 set_used_network(true);
303 return sync_context_->GetDriveService(); 320 return sync_context_->GetDriveService();
304 } 321 }
305 322
306 MetadataDatabase* ConflictResolver::metadata_database() { 323 MetadataDatabase* ConflictResolver::metadata_database() {
307 return sync_context_->GetMetadataDatabase(); 324 return sync_context_->GetMetadataDatabase();
308 } 325 }
309 326
310 } // namespace drive_backend 327 } // namespace drive_backend
311 } // namespace sync_file_system 328 } // namespace sync_file_system
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698