OLD | NEW |
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 <stdint.h> | 7 #include <stdint.h> |
| 8 #include <utility> |
8 | 9 |
9 #include "base/callback.h" | 10 #include "base/callback.h" |
10 #include "base/format_macros.h" | 11 #include "base/format_macros.h" |
11 #include "base/location.h" | 12 #include "base/location.h" |
12 #include "base/logging.h" | 13 #include "base/logging.h" |
13 #include "base/strings/stringprintf.h" | 14 #include "base/strings/stringprintf.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" |
(...skipping 13 matching lines...) Expand all Loading... |
31 weak_ptr_factory_(this) {} | 32 weak_ptr_factory_(this) {} |
32 | 33 |
33 ConflictResolver::~ConflictResolver() {} | 34 ConflictResolver::~ConflictResolver() {} |
34 | 35 |
35 void ConflictResolver::RunPreflight(scoped_ptr<SyncTaskToken> token) { | 36 void ConflictResolver::RunPreflight(scoped_ptr<SyncTaskToken> token) { |
36 token->InitializeTaskLog("Conflict Resolution"); | 37 token->InitializeTaskLog("Conflict Resolution"); |
37 | 38 |
38 scoped_ptr<TaskBlocker> task_blocker(new TaskBlocker); | 39 scoped_ptr<TaskBlocker> task_blocker(new TaskBlocker); |
39 task_blocker->exclusive = true; | 40 task_blocker->exclusive = true; |
40 SyncTaskManager::UpdateTaskBlocker( | 41 SyncTaskManager::UpdateTaskBlocker( |
41 token.Pass(), task_blocker.Pass(), | 42 std::move(token), std::move(task_blocker), |
42 base::Bind(&ConflictResolver::RunExclusive, | 43 base::Bind(&ConflictResolver::RunExclusive, |
43 weak_ptr_factory_.GetWeakPtr())); | 44 weak_ptr_factory_.GetWeakPtr())); |
44 } | 45 } |
45 | 46 |
46 void ConflictResolver::RunExclusive(scoped_ptr<SyncTaskToken> token) { | 47 void ConflictResolver::RunExclusive(scoped_ptr<SyncTaskToken> token) { |
47 if (!IsContextReady()) { | 48 if (!IsContextReady()) { |
48 SyncTaskManager::NotifyTaskDone(token.Pass(), SYNC_STATUS_FAILED); | 49 SyncTaskManager::NotifyTaskDone(std::move(token), SYNC_STATUS_FAILED); |
49 return; | 50 return; |
50 } | 51 } |
51 | 52 |
52 // Conflict resolution should be invoked on clean tree. | 53 // Conflict resolution should be invoked on clean tree. |
53 if (metadata_database()->HasDirtyTracker()) { | 54 if (metadata_database()->HasDirtyTracker()) { |
54 SyncTaskManager::NotifyTaskDone(token.Pass(), SYNC_STATUS_RETRY); | 55 SyncTaskManager::NotifyTaskDone(std::move(token), SYNC_STATUS_RETRY); |
55 return; | 56 return; |
56 } | 57 } |
57 | 58 |
58 TrackerIDSet trackers; | 59 TrackerIDSet trackers; |
59 if (metadata_database()->GetMultiParentFileTrackers( | 60 if (metadata_database()->GetMultiParentFileTrackers( |
60 &target_file_id_, &trackers)) { | 61 &target_file_id_, &trackers)) { |
61 DCHECK_LT(1u, trackers.size()); | 62 DCHECK_LT(1u, trackers.size()); |
62 if (!trackers.has_active()) { | 63 if (!trackers.has_active()) { |
63 NOTREACHED(); | 64 NOTREACHED(); |
64 SyncTaskManager::NotifyTaskDone(token.Pass(), SYNC_STATUS_FAILED); | 65 SyncTaskManager::NotifyTaskDone(std::move(token), SYNC_STATUS_FAILED); |
65 return; | 66 return; |
66 } | 67 } |
67 | 68 |
68 token->RecordLog(base::StringPrintf( | 69 token->RecordLog(base::StringPrintf( |
69 "Detected multi-parent trackers (active tracker_id=%" PRId64 ")", | 70 "Detected multi-parent trackers (active tracker_id=%" PRId64 ")", |
70 trackers.active_tracker())); | 71 trackers.active_tracker())); |
71 | 72 |
72 DCHECK(trackers.has_active()); | 73 DCHECK(trackers.has_active()); |
73 for (TrackerIDSet::const_iterator itr = trackers.begin(); | 74 for (TrackerIDSet::const_iterator itr = trackers.begin(); |
74 itr != trackers.end(); ++itr) { | 75 itr != trackers.end(); ++itr) { |
75 FileTracker tracker; | 76 FileTracker tracker; |
76 if (!metadata_database()->FindTrackerByTrackerID(*itr, &tracker)) { | 77 if (!metadata_database()->FindTrackerByTrackerID(*itr, &tracker)) { |
77 NOTREACHED(); | 78 NOTREACHED(); |
78 continue; | 79 continue; |
79 } | 80 } |
80 | 81 |
81 if (tracker.active()) | 82 if (tracker.active()) |
82 continue; | 83 continue; |
83 | 84 |
84 FileTracker parent_tracker; | 85 FileTracker parent_tracker; |
85 bool should_success = metadata_database()->FindTrackerByTrackerID( | 86 bool should_success = metadata_database()->FindTrackerByTrackerID( |
86 tracker.parent_tracker_id(), &parent_tracker); | 87 tracker.parent_tracker_id(), &parent_tracker); |
87 if (!should_success) { | 88 if (!should_success) { |
88 NOTREACHED(); | 89 NOTREACHED(); |
89 SyncTaskManager::NotifyTaskDone(token.Pass(), SYNC_STATUS_FAILED); | 90 SyncTaskManager::NotifyTaskDone(std::move(token), SYNC_STATUS_FAILED); |
90 return; | 91 return; |
91 } | 92 } |
92 parents_to_remove_.push_back(parent_tracker.file_id()); | 93 parents_to_remove_.push_back(parent_tracker.file_id()); |
93 } | 94 } |
94 DetachFromNonPrimaryParents(token.Pass()); | 95 DetachFromNonPrimaryParents(std::move(token)); |
95 return; | 96 return; |
96 } | 97 } |
97 | 98 |
98 if (metadata_database()->GetConflictingTrackers(&trackers)) { | 99 if (metadata_database()->GetConflictingTrackers(&trackers)) { |
99 target_file_id_ = PickPrimaryFile(trackers); | 100 target_file_id_ = PickPrimaryFile(trackers); |
100 DCHECK(!target_file_id_.empty()); | 101 DCHECK(!target_file_id_.empty()); |
101 int64_t primary_tracker_id = -1; | 102 int64_t primary_tracker_id = -1; |
102 for (TrackerIDSet::const_iterator itr = trackers.begin(); | 103 for (TrackerIDSet::const_iterator itr = trackers.begin(); |
103 itr != trackers.end(); ++itr) { | 104 itr != trackers.end(); ++itr) { |
104 FileTracker tracker; | 105 FileTracker tracker; |
105 if (!metadata_database()->FindTrackerByTrackerID(*itr, &tracker)) { | 106 if (!metadata_database()->FindTrackerByTrackerID(*itr, &tracker)) { |
106 NOTREACHED(); | 107 NOTREACHED(); |
107 continue; | 108 continue; |
108 } | 109 } |
109 if (tracker.file_id() != target_file_id_) { | 110 if (tracker.file_id() != target_file_id_) { |
110 non_primary_file_ids_.push_back( | 111 non_primary_file_ids_.push_back( |
111 std::make_pair(tracker.file_id(), tracker.synced_details().etag())); | 112 std::make_pair(tracker.file_id(), tracker.synced_details().etag())); |
112 } else { | 113 } else { |
113 primary_tracker_id = tracker.tracker_id(); | 114 primary_tracker_id = tracker.tracker_id(); |
114 } | 115 } |
115 } | 116 } |
116 | 117 |
117 token->RecordLog(base::StringPrintf( | 118 token->RecordLog(base::StringPrintf( |
118 "Detected %" PRIuS " conflicting trackers " | 119 "Detected %" PRIuS " conflicting trackers " |
119 "(primary tracker_id=%" PRId64 ")", | 120 "(primary tracker_id=%" PRId64 ")", |
120 non_primary_file_ids_.size(), primary_tracker_id)); | 121 non_primary_file_ids_.size(), primary_tracker_id)); |
121 | 122 |
122 RemoveNonPrimaryFiles(token.Pass()); | 123 RemoveNonPrimaryFiles(std::move(token)); |
123 return; | 124 return; |
124 } | 125 } |
125 | 126 |
126 SyncTaskManager::NotifyTaskDone(token.Pass(), SYNC_STATUS_NO_CONFLICT); | 127 SyncTaskManager::NotifyTaskDone(std::move(token), SYNC_STATUS_NO_CONFLICT); |
127 } | 128 } |
128 | 129 |
129 void ConflictResolver::DetachFromNonPrimaryParents( | 130 void ConflictResolver::DetachFromNonPrimaryParents( |
130 scoped_ptr<SyncTaskToken> token) { | 131 scoped_ptr<SyncTaskToken> token) { |
131 DCHECK(!parents_to_remove_.empty()); | 132 DCHECK(!parents_to_remove_.empty()); |
132 | 133 |
133 // TODO(tzik): Check if ETag match is available for | 134 // TODO(tzik): Check if ETag match is available for |
134 // RemoteResourceFromDirectory. | 135 // RemoteResourceFromDirectory. |
135 std::string parent_folder_id = parents_to_remove_.back(); | 136 std::string parent_folder_id = parents_to_remove_.back(); |
136 parents_to_remove_.pop_back(); | 137 parents_to_remove_.pop_back(); |
137 | 138 |
138 token->RecordLog(base::StringPrintf( | 139 token->RecordLog(base::StringPrintf( |
139 "Detach %s from %s", | 140 "Detach %s from %s", |
140 target_file_id_.c_str(), parent_folder_id.c_str())); | 141 target_file_id_.c_str(), parent_folder_id.c_str())); |
141 | 142 |
142 drive_service()->RemoveResourceFromDirectory( | 143 drive_service()->RemoveResourceFromDirectory( |
143 parent_folder_id, target_file_id_, | 144 parent_folder_id, target_file_id_, |
144 base::Bind(&ConflictResolver::DidDetachFromParent, | 145 base::Bind(&ConflictResolver::DidDetachFromParent, |
145 weak_ptr_factory_.GetWeakPtr(), | 146 weak_ptr_factory_.GetWeakPtr(), |
146 base::Passed(&token))); | 147 base::Passed(&token))); |
147 } | 148 } |
148 | 149 |
149 void ConflictResolver::DidDetachFromParent( | 150 void ConflictResolver::DidDetachFromParent( |
150 scoped_ptr<SyncTaskToken> token, | 151 scoped_ptr<SyncTaskToken> token, |
151 google_apis::DriveApiErrorCode error) { | 152 google_apis::DriveApiErrorCode error) { |
152 SyncStatusCode status = DriveApiErrorCodeToSyncStatusCode(error); | 153 SyncStatusCode status = DriveApiErrorCodeToSyncStatusCode(error); |
153 if (status != SYNC_STATUS_OK) { | 154 if (status != SYNC_STATUS_OK) { |
154 SyncTaskManager::NotifyTaskDone(token.Pass(), status); | 155 SyncTaskManager::NotifyTaskDone(std::move(token), status); |
155 return; | 156 return; |
156 } | 157 } |
157 | 158 |
158 if (!parents_to_remove_.empty()) { | 159 if (!parents_to_remove_.empty()) { |
159 DetachFromNonPrimaryParents(token.Pass()); | 160 DetachFromNonPrimaryParents(std::move(token)); |
160 return; | 161 return; |
161 } | 162 } |
162 | 163 |
163 SyncTaskManager::NotifyTaskDone(token.Pass(), SYNC_STATUS_OK); | 164 SyncTaskManager::NotifyTaskDone(std::move(token), SYNC_STATUS_OK); |
164 } | 165 } |
165 | 166 |
166 std::string ConflictResolver::PickPrimaryFile(const TrackerIDSet& trackers) { | 167 std::string ConflictResolver::PickPrimaryFile(const TrackerIDSet& trackers) { |
167 scoped_ptr<FileMetadata> primary; | 168 scoped_ptr<FileMetadata> primary; |
168 for (TrackerIDSet::const_iterator itr = trackers.begin(); | 169 for (TrackerIDSet::const_iterator itr = trackers.begin(); |
169 itr != trackers.end(); ++itr) { | 170 itr != trackers.end(); ++itr) { |
170 FileTracker tracker; | 171 FileTracker tracker; |
171 if (!metadata_database()->FindTrackerByTrackerID(*itr, &tracker)) { | 172 if (!metadata_database()->FindTrackerByTrackerID(*itr, &tracker)) { |
172 NOTREACHED(); | 173 NOTREACHED(); |
173 continue; | 174 continue; |
174 } | 175 } |
175 | 176 |
176 scoped_ptr<FileMetadata> file_metadata(new FileMetadata); | 177 scoped_ptr<FileMetadata> file_metadata(new FileMetadata); |
177 if (!metadata_database()->FindFileByFileID( | 178 if (!metadata_database()->FindFileByFileID( |
178 tracker.file_id(), file_metadata.get())) { | 179 tracker.file_id(), file_metadata.get())) { |
179 NOTREACHED(); | 180 NOTREACHED(); |
180 continue; | 181 continue; |
181 } | 182 } |
182 | 183 |
183 if (!primary) { | 184 if (!primary) { |
184 primary = file_metadata.Pass(); | 185 primary = std::move(file_metadata); |
185 continue; | 186 continue; |
186 } | 187 } |
187 | 188 |
188 DCHECK(primary->details().file_kind() == FILE_KIND_FILE || | 189 DCHECK(primary->details().file_kind() == FILE_KIND_FILE || |
189 primary->details().file_kind() == FILE_KIND_FOLDER); | 190 primary->details().file_kind() == FILE_KIND_FOLDER); |
190 DCHECK(file_metadata->details().file_kind() == FILE_KIND_FILE || | 191 DCHECK(file_metadata->details().file_kind() == FILE_KIND_FILE || |
191 file_metadata->details().file_kind() == FILE_KIND_FOLDER); | 192 file_metadata->details().file_kind() == FILE_KIND_FOLDER); |
192 | 193 |
193 if (primary->details().file_kind() == FILE_KIND_FILE) { | 194 if (primary->details().file_kind() == FILE_KIND_FILE) { |
194 if (file_metadata->details().file_kind() == FILE_KIND_FOLDER) { | 195 if (file_metadata->details().file_kind() == FILE_KIND_FOLDER) { |
195 // Prioritize folders over regular files. | 196 // Prioritize folders over regular files. |
196 primary = file_metadata.Pass(); | 197 primary = std::move(file_metadata); |
197 continue; | 198 continue; |
198 } | 199 } |
199 | 200 |
200 DCHECK(file_metadata->details().file_kind() == FILE_KIND_FILE); | 201 DCHECK(file_metadata->details().file_kind() == FILE_KIND_FILE); |
201 if (primary->details().modification_time() < | 202 if (primary->details().modification_time() < |
202 file_metadata->details().modification_time()) { | 203 file_metadata->details().modification_time()) { |
203 // Prioritize last write for regular files. | 204 // Prioritize last write for regular files. |
204 primary = file_metadata.Pass(); | 205 primary = std::move(file_metadata); |
205 continue; | 206 continue; |
206 } | 207 } |
207 | 208 |
208 continue; | 209 continue; |
209 } | 210 } |
210 | 211 |
211 DCHECK(primary->details().file_kind() == FILE_KIND_FOLDER); | 212 DCHECK(primary->details().file_kind() == FILE_KIND_FOLDER); |
212 if (file_metadata->details().file_kind() == FILE_KIND_FILE) { | 213 if (file_metadata->details().file_kind() == FILE_KIND_FILE) { |
213 // Prioritize folders over regular files. | 214 // Prioritize folders over regular files. |
214 continue; | 215 continue; |
215 } | 216 } |
216 | 217 |
217 DCHECK(file_metadata->details().file_kind() == FILE_KIND_FOLDER); | 218 DCHECK(file_metadata->details().file_kind() == FILE_KIND_FOLDER); |
218 if (primary->details().creation_time() > | 219 if (primary->details().creation_time() > |
219 file_metadata->details().creation_time()) { | 220 file_metadata->details().creation_time()) { |
220 // Prioritize first create for folders. | 221 // Prioritize first create for folders. |
221 primary = file_metadata.Pass(); | 222 primary = std::move(file_metadata); |
222 continue; | 223 continue; |
223 } | 224 } |
224 } | 225 } |
225 | 226 |
226 if (primary) | 227 if (primary) |
227 return primary->file_id(); | 228 return primary->file_id(); |
228 return std::string(); | 229 return std::string(); |
229 } | 230 } |
230 | 231 |
231 void ConflictResolver::RemoveNonPrimaryFiles(scoped_ptr<SyncTaskToken> token) { | 232 void ConflictResolver::RemoveNonPrimaryFiles(scoped_ptr<SyncTaskToken> token) { |
(...skipping 15 matching lines...) Expand all Loading... |
247 base::Bind(&ConflictResolver::DidRemoveFile, | 248 base::Bind(&ConflictResolver::DidRemoveFile, |
248 weak_ptr_factory_.GetWeakPtr(), | 249 weak_ptr_factory_.GetWeakPtr(), |
249 base::Passed(&token), file_id)); | 250 base::Passed(&token), file_id)); |
250 } | 251 } |
251 | 252 |
252 void ConflictResolver::DidRemoveFile(scoped_ptr<SyncTaskToken> token, | 253 void ConflictResolver::DidRemoveFile(scoped_ptr<SyncTaskToken> token, |
253 const std::string& file_id, | 254 const std::string& file_id, |
254 google_apis::DriveApiErrorCode error) { | 255 google_apis::DriveApiErrorCode error) { |
255 if (error == google_apis::HTTP_PRECONDITION || | 256 if (error == google_apis::HTTP_PRECONDITION || |
256 error == google_apis::HTTP_CONFLICT) { | 257 error == google_apis::HTTP_CONFLICT) { |
257 UpdateFileMetadata(file_id, token.Pass()); | 258 UpdateFileMetadata(file_id, std::move(token)); |
258 return; | 259 return; |
259 } | 260 } |
260 | 261 |
261 SyncStatusCode status = DriveApiErrorCodeToSyncStatusCode(error); | 262 SyncStatusCode status = DriveApiErrorCodeToSyncStatusCode(error); |
262 if (status != SYNC_STATUS_OK && error != google_apis::HTTP_NOT_FOUND) { | 263 if (status != SYNC_STATUS_OK && error != google_apis::HTTP_NOT_FOUND) { |
263 SyncTaskManager::NotifyTaskDone(token.Pass(), status); | 264 SyncTaskManager::NotifyTaskDone(std::move(token), status); |
264 return; | 265 return; |
265 } | 266 } |
266 | 267 |
267 deleted_file_ids_.push_back(file_id); | 268 deleted_file_ids_.push_back(file_id); |
268 if (!non_primary_file_ids_.empty()) { | 269 if (!non_primary_file_ids_.empty()) { |
269 RemoveNonPrimaryFiles(token.Pass()); | 270 RemoveNonPrimaryFiles(std::move(token)); |
270 return; | 271 return; |
271 } | 272 } |
272 | 273 |
273 status = metadata_database()->UpdateByDeletedRemoteFileList( | 274 status = metadata_database()->UpdateByDeletedRemoteFileList( |
274 deleted_file_ids_); | 275 deleted_file_ids_); |
275 SyncTaskManager::NotifyTaskDone(token.Pass(), status); | 276 SyncTaskManager::NotifyTaskDone(std::move(token), status); |
276 } | 277 } |
277 | 278 |
278 bool ConflictResolver::IsContextReady() { | 279 bool ConflictResolver::IsContextReady() { |
279 return sync_context_->GetDriveService() && | 280 return sync_context_->GetDriveService() && |
280 sync_context_->GetMetadataDatabase(); | 281 sync_context_->GetMetadataDatabase(); |
281 } | 282 } |
282 | 283 |
283 void ConflictResolver::UpdateFileMetadata( | 284 void ConflictResolver::UpdateFileMetadata( |
284 const std::string& file_id, | 285 const std::string& file_id, |
285 scoped_ptr<SyncTaskToken> token) { | 286 scoped_ptr<SyncTaskToken> token) { |
286 drive_service()->GetFileResource( | 287 drive_service()->GetFileResource( |
287 file_id, | 288 file_id, |
288 base::Bind(&ConflictResolver::DidGetRemoteMetadata, | 289 base::Bind(&ConflictResolver::DidGetRemoteMetadata, |
289 weak_ptr_factory_.GetWeakPtr(), file_id, | 290 weak_ptr_factory_.GetWeakPtr(), file_id, |
290 base::Passed(&token))); | 291 base::Passed(&token))); |
291 } | 292 } |
292 | 293 |
293 void ConflictResolver::DidGetRemoteMetadata( | 294 void ConflictResolver::DidGetRemoteMetadata( |
294 const std::string& file_id, | 295 const std::string& file_id, |
295 scoped_ptr<SyncTaskToken> token, | 296 scoped_ptr<SyncTaskToken> token, |
296 google_apis::DriveApiErrorCode error, | 297 google_apis::DriveApiErrorCode error, |
297 scoped_ptr<google_apis::FileResource> entry) { | 298 scoped_ptr<google_apis::FileResource> entry) { |
298 SyncStatusCode status = DriveApiErrorCodeToSyncStatusCode(error); | 299 SyncStatusCode status = DriveApiErrorCodeToSyncStatusCode(error); |
299 if (status != SYNC_STATUS_OK && error != google_apis::HTTP_NOT_FOUND) { | 300 if (status != SYNC_STATUS_OK && error != google_apis::HTTP_NOT_FOUND) { |
300 SyncTaskManager::NotifyTaskDone(token.Pass(), status); | 301 SyncTaskManager::NotifyTaskDone(std::move(token), status); |
301 return; | 302 return; |
302 } | 303 } |
303 | 304 |
304 if (error != google_apis::HTTP_NOT_FOUND) { | 305 if (error != google_apis::HTTP_NOT_FOUND) { |
305 status = metadata_database()->UpdateByDeletedRemoteFile(file_id); | 306 status = metadata_database()->UpdateByDeletedRemoteFile(file_id); |
306 SyncTaskManager::NotifyTaskDone(token.Pass(), status); | 307 SyncTaskManager::NotifyTaskDone(std::move(token), status); |
307 return; | 308 return; |
308 } | 309 } |
309 | 310 |
310 if (!entry) { | 311 if (!entry) { |
311 NOTREACHED(); | 312 NOTREACHED(); |
312 SyncTaskManager::NotifyTaskDone(token.Pass(), SYNC_STATUS_FAILED); | 313 SyncTaskManager::NotifyTaskDone(std::move(token), SYNC_STATUS_FAILED); |
313 return; | 314 return; |
314 } | 315 } |
315 | 316 |
316 status = metadata_database()->UpdateByFileResource(*entry); | 317 status = metadata_database()->UpdateByFileResource(*entry); |
317 SyncTaskManager::NotifyTaskDone(token.Pass(), status); | 318 SyncTaskManager::NotifyTaskDone(std::move(token), status); |
318 } | 319 } |
319 | 320 |
320 drive::DriveServiceInterface* ConflictResolver::drive_service() { | 321 drive::DriveServiceInterface* ConflictResolver::drive_service() { |
321 set_used_network(true); | 322 set_used_network(true); |
322 return sync_context_->GetDriveService(); | 323 return sync_context_->GetDriveService(); |
323 } | 324 } |
324 | 325 |
325 MetadataDatabase* ConflictResolver::metadata_database() { | 326 MetadataDatabase* ConflictResolver::metadata_database() { |
326 return sync_context_->GetMetadataDatabase(); | 327 return sync_context_->GetMetadataDatabase(); |
327 } | 328 } |
328 | 329 |
329 } // namespace drive_backend | 330 } // namespace drive_backend |
330 } // namespace sync_file_system | 331 } // namespace sync_file_system |
OLD | NEW |