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

Side by Side Diff: chrome/browser/chromeos/drive/change_list_loader.cc

Issue 13896005: Sort methods of drive::ChangeListLoader. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 8 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 (c) 2012 The Chromium Authors. All rights reserved. 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 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/chromeos/drive/change_list_loader.h" 5 #include "chrome/browser/chromeos/drive/change_list_loader.h"
6 6
7 #include <set> 7 #include <set>
8 8
9 #include "base/callback.h" 9 #include "base/callback.h"
10 #include "base/metrics/histogram.h" 10 #include "base/metrics/histogram.h"
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
45 void ChangeListLoader::AddObserver(ChangeListLoaderObserver* observer) { 45 void ChangeListLoader::AddObserver(ChangeListLoaderObserver* observer) {
46 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 46 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
47 observers_.AddObserver(observer); 47 observers_.AddObserver(observer);
48 } 48 }
49 49
50 void ChangeListLoader::RemoveObserver(ChangeListLoaderObserver* observer) { 50 void ChangeListLoader::RemoveObserver(ChangeListLoaderObserver* observer) {
51 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 51 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
52 observers_.RemoveObserver(observer); 52 observers_.RemoveObserver(observer);
53 } 53 }
54 54
55 void ChangeListLoader::LoadIfNeeded(
56 const DirectoryFetchInfo& directory_fetch_info,
57 const FileOperationCallback& callback) {
58 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
59 DCHECK(!callback.is_null());
60
61 // If feed has already been loaded, for normal feed fetch (= empty
62 // directory_fetch_info), we have nothing to do. For "fast fetch", we need to
63 // schedule a fetching if a feed refresh is currently running, because we
64 // don't want to wait a possibly large delta feed to arrive.
65 if (loaded_ && (directory_fetch_info.empty() || !IsRefreshing())) {
66 base::MessageLoopProxy::current()->PostTask(
67 FROM_HERE,
68 base::Bind(callback, DRIVE_FILE_OK));
69 return;
70 }
71 Load(directory_fetch_info, callback);
72 }
73
74 void ChangeListLoader::CheckForUpdates(const FileOperationCallback& callback) {
75 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
76 DCHECK(!callback.is_null());
77
78 if (loaded_ && !IsRefreshing())
79 Load(DirectoryFetchInfo(), callback);
80 }
81
82 void ChangeListLoader::LoadDirectoryFromServer(
83 const std::string& directory_resource_id,
84 const FileOperationCallback& callback) {
85 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
86 DCHECK(!callback.is_null());
87
88 // First fetch the latest changestamp to see if this directory needs to be
89 // updated.
90 scheduler_->GetAboutResource(
91 base::Bind(
92 &ChangeListLoader::LoadDirectoryFromServerAfterGetAbout,
93 weak_ptr_factory_.GetWeakPtr(),
94 directory_resource_id,
95 callback));
96 }
97
98 void ChangeListLoader::SearchFromServer(
99 const std::string& search_query,
100 const GURL& next_feed,
101 const LoadFeedListCallback& callback) {
102 DCHECK(!callback.is_null());
103
104 if (next_feed.is_empty()) {
105 // This is first request for the |search_query|.
106 scheduler_->Search(
107 search_query,
108 base::Bind(&ChangeListLoader::SearchFromServerAfterGetResourceList,
109 weak_ptr_factory_.GetWeakPtr(), callback));
110 } else {
111 // There is the remaining result so fetch it.
112 scheduler_->ContinueGetResourceList(
113 next_feed,
114 base::Bind(&ChangeListLoader::SearchFromServerAfterGetResourceList,
115 weak_ptr_factory_.GetWeakPtr(), callback));
116 }
117 }
118
119 void ChangeListLoader::UpdateFromFeed(
120 scoped_ptr<google_apis::AboutResource> about_resource,
121 ScopedVector<ChangeList> change_lists,
122 bool is_delta_feed,
123 const base::Closure& callback) {
124 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
125 DCHECK(!callback.is_null());
126
127 change_list_processor_.reset(new ChangeListProcessor(resource_metadata_));
128 // Don't send directory content change notification while performing
129 // the initial content retrieval.
130 const bool should_notify_changed_directories = is_delta_feed;
131
132 change_list_processor_->ApplyFeeds(
133 about_resource.Pass(),
134 change_lists.Pass(),
135 is_delta_feed,
136 base::Bind(&ChangeListLoader::NotifyDirectoryChangedAfterApplyFeed,
137 weak_ptr_factory_.GetWeakPtr(),
138 should_notify_changed_directories,
139 callback));
140 }
141
142 void ChangeListLoader::Load(const DirectoryFetchInfo& directory_fetch_info,
143 const FileOperationCallback& callback) {
144 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
145 DCHECK(!callback.is_null());
146
147 // Check if this is the first time this ChangeListLoader do loading.
148 // Note: IsRefreshing() depends on pending_load_callback_ so check in advance.
149 const bool is_initial_load = (!loaded_ && !IsRefreshing());
150
151 // Register the callback function to be called when it is loaded.
152 const std::string& resource_id = directory_fetch_info.resource_id();
153 pending_load_callback_[resource_id].push_back(callback);
154
155 // If loading task for |resource_id| is already running, do nothing.
156 if (pending_load_callback_[resource_id].size() > 1)
157 return;
158
159 // For initial loading, even for directory fetching, we do load the full
160 // feed from the server to sync up. So we register a dummy callback to
161 // indicate that update for full hierarchy is running.
162 if (is_initial_load && !resource_id.empty()) {
163 pending_load_callback_[""].push_back(
164 base::Bind(&util::EmptyFileOperationCallback));
165 }
166
167 // Check the current status of local metadata, and start loading if needed.
168 resource_metadata_->GetLargestChangestamp(
169 base::Bind(is_initial_load ? &ChangeListLoader::DoInitialLoad
170 : &ChangeListLoader::DoUpdateLoad,
171 weak_ptr_factory_.GetWeakPtr(),
172 directory_fetch_info));
173 }
174
175 void ChangeListLoader::DoInitialLoad(
176 const DirectoryFetchInfo& directory_fetch_info,
177 int64 local_changestamp) {
178 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
179
180 if (local_changestamp > 0) {
181 // The local data is usable. Flush callbacks to tell loading was successful.
182 OnChangeListLoadComplete(DRIVE_FILE_OK);
183
184 // Continues to load from server in background.
185 // Put dummy callbacks to indicate that fetching is still continuing.
186 pending_load_callback_[directory_fetch_info.resource_id()].push_back(
187 base::Bind(&util::EmptyFileOperationCallback));
188 if (!directory_fetch_info.empty()) {
189 pending_load_callback_[""].push_back(
190 base::Bind(&util::EmptyFileOperationCallback));
191 }
192 }
193 LoadFromServerIfNeeded(directory_fetch_info, local_changestamp);
194 }
195
196 void ChangeListLoader::DoUpdateLoad(
197 const DirectoryFetchInfo& directory_fetch_info,
198 int64 local_changestamp) {
199 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
200
201 if (directory_fetch_info.empty()) {
202 LoadFromServerIfNeeded(directory_fetch_info, local_changestamp);
203 } else {
204 // Note: CheckChangestampAndLoadDirectoryIfNeeded regards
205 // last_know_remote_changestamp_ as the remote changestamp. To be precise,
206 // we need to call GetAboutResource() here, as we do in other places like
207 // LoadFromServerIfNeeded or LoadFromDirectory. However,
208 // - It is costly to do GetAboutResource HTTP request every time.
209 // - The chance using an old value is small; it only happens when
210 // LoadIfNeeded is called during one GetAboutResource roundtrip time
211 // of a feed fetching.
212 // - Even if the value is old, it just marks the directory as older. It may
213 // trigger one future unnecessary re-fetch, but it'll never lose data.
214 CheckChangestampAndLoadDirectoryIfNeeed(
215 directory_fetch_info,
216 local_changestamp,
217 base::Bind(&ChangeListLoader::OnDirectoryLoadComplete,
218 weak_ptr_factory_.GetWeakPtr(),
219 directory_fetch_info));
220 }
221 }
222
223 void ChangeListLoader::OnChangeListLoadComplete(DriveFileError error) {
224 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
225
226 if (!loaded_ && error == DRIVE_FILE_OK) {
227 loaded_ = true;
228 FOR_EACH_OBSERVER(ChangeListLoaderObserver,
229 observers_,
230 OnInitialFeedLoaded());
231 }
232
233 for (LoadCallbackMap::iterator it = pending_load_callback_.begin();
234 it != pending_load_callback_.end(); ++it) {
235 const std::vector<FileOperationCallback>& callbacks = it->second;
236 for (size_t i = 0; i < callbacks.size(); ++i) {
237 base::MessageLoopProxy::current()->PostTask(
238 FROM_HERE,
239 base::Bind(callbacks[i], error));
240 }
241 }
242 pending_load_callback_.clear();
243 }
244
245 void ChangeListLoader::OnDirectoryLoadComplete(
246 const DirectoryFetchInfo& directory_fetch_info,
247 DriveFileError error) {
248 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
249
250 DVLOG_IF(1, error == DRIVE_FILE_OK) << "Fast-fetch was successful: "
251 << directory_fetch_info.ToString();
252
253 const std::string& resource_id = directory_fetch_info.resource_id();
254 LoadCallbackMap::iterator it = pending_load_callback_.find(resource_id);
255 if (it != pending_load_callback_.end()) {
256 DVLOG(1) << "Running callback for " << resource_id;
257 const std::vector<FileOperationCallback>& callbacks = it->second;
258 for (size_t i = 0; i < callbacks.size(); ++i) {
259 base::MessageLoopProxy::current()->PostTask(
260 FROM_HERE,
261 base::Bind(callbacks[i], error));
262 }
263 pending_load_callback_.erase(it);
264 }
265 }
266
55 void ChangeListLoader::LoadFromServerIfNeeded( 267 void ChangeListLoader::LoadFromServerIfNeeded(
56 const DirectoryFetchInfo& directory_fetch_info, 268 const DirectoryFetchInfo& directory_fetch_info,
57 int64 local_changestamp) { 269 int64 local_changestamp) {
58 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 270 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
59 271
60 // Drive v2 needs a separate application list fetch operation. 272 // Drive v2 needs a separate application list fetch operation.
61 // On GData WAPI, it is not necessary in theory, because the response 273 // On GData WAPI, it is not necessary in theory, because the response
62 // of account metadata can include both about account information (such as 274 // of account metadata can include both about account information (such as
63 // quota) and an application list at once. 275 // quota) and an application list at once.
64 // However, for Drive API v2 migration, we connect to the server twice 276 // However, for Drive API v2 migration, we connect to the server twice
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
133 local_changestamp, 345 local_changestamp,
134 base::Bind( 346 base::Bind(
135 &ChangeListLoader::LoadChangeListFromServerAfterLoadDirectory, 347 &ChangeListLoader::LoadChangeListFromServerAfterLoadDirectory,
136 weak_ptr_factory_.GetWeakPtr(), 348 weak_ptr_factory_.GetWeakPtr(),
137 directory_fetch_info, 349 directory_fetch_info,
138 base::Passed(&about_resource), 350 base::Passed(&about_resource),
139 start_changestamp)); 351 start_changestamp));
140 } 352 }
141 } 353 }
142 354
355 void ChangeListLoader::LoadChangeListFromServerAfterLoadDirectory(
356 const DirectoryFetchInfo& directory_fetch_info,
357 scoped_ptr<google_apis::AboutResource> about_resource,
358 int64 start_changestamp,
359 DriveFileError error) {
360 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
361
362 if (error == DRIVE_FILE_OK) {
363 // The directory fast-fetch succeeded. Runs the callbacks waiting for the
364 // directory loading. If failed, do not flush so they're run after the
365 // change list loading is complete.
366 OnDirectoryLoadComplete(directory_fetch_info, DRIVE_FILE_OK);
367 }
368 LoadChangeListFromServer(about_resource.Pass(), start_changestamp);
369 }
370
143 void ChangeListLoader::LoadChangeListFromServer( 371 void ChangeListLoader::LoadChangeListFromServer(
144 scoped_ptr<google_apis::AboutResource> about_resource, 372 scoped_ptr<google_apis::AboutResource> about_resource,
145 int64 start_changestamp) { 373 int64 start_changestamp) {
146 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 374 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
147 375
148 bool is_delta_feed = start_changestamp != 0; 376 bool is_delta_feed = start_changestamp != 0;
149 const LoadFeedListCallback& completion_callback = 377 const LoadFeedListCallback& completion_callback =
150 base::Bind(&ChangeListLoader::UpdateMetadataFromFeedAfterLoadFromServer, 378 base::Bind(&ChangeListLoader::UpdateMetadataFromFeedAfterLoadFromServer,
151 weak_ptr_factory_.GetWeakPtr(), 379 weak_ptr_factory_.GetWeakPtr(),
152 base::Passed(&about_resource), 380 base::Passed(&about_resource),
(...skipping 11 matching lines...) Expand all
164 // This is full feed fetch. 392 // This is full feed fetch.
165 scheduler_->GetAllResourceList( 393 scheduler_->GetAllResourceList(
166 base::Bind(&ChangeListLoader::OnGetResourceList, 394 base::Bind(&ChangeListLoader::OnGetResourceList,
167 weak_ptr_factory_.GetWeakPtr(), 395 weak_ptr_factory_.GetWeakPtr(),
168 base::Passed(ScopedVector<ChangeList>()), 396 base::Passed(ScopedVector<ChangeList>()),
169 completion_callback, 397 completion_callback,
170 start_time)); 398 start_time));
171 } 399 }
172 } 400 }
173 401
174 void ChangeListLoader::LoadChangeListFromServerAfterLoadDirectory(
175 const DirectoryFetchInfo& directory_fetch_info,
176 scoped_ptr<google_apis::AboutResource> about_resource,
177 int64 start_changestamp,
178 DriveFileError error) {
179 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
180
181 if (error == DRIVE_FILE_OK) {
182 // The directory fast-fetch succeeded. Runs the callbacks waiting for the
183 // directory loading. If failed, do not flush so they're run after the
184 // change list loading is complete.
185 OnDirectoryLoadComplete(directory_fetch_info, DRIVE_FILE_OK);
186 }
187 LoadChangeListFromServer(about_resource.Pass(), start_changestamp);
188 }
189
190 void ChangeListLoader::SearchFromServerAfterGetResourceList(
191 const LoadFeedListCallback& callback,
192 google_apis::GDataErrorCode status,
193 scoped_ptr<google_apis::ResourceList> resource_list) {
194 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
195 DCHECK(!callback.is_null());
196
197 DriveFileError error = util::GDataToDriveFileError(status);
198 if (error != DRIVE_FILE_OK) {
199 callback.Run(ScopedVector<ChangeList>(), error);
200 return;
201 }
202
203 DCHECK(resource_list);
204
205 ScopedVector<ChangeList> change_lists;
206 change_lists.push_back(new ChangeList(*resource_list));
207 callback.Run(change_lists.Pass(), DRIVE_FILE_OK);
208 }
209
210 void ChangeListLoader::OnGetAppList(google_apis::GDataErrorCode status,
211 scoped_ptr<google_apis::AppList> app_list) {
212 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
213
214 DriveFileError error = util::GDataToDriveFileError(status);
215 if (error != DRIVE_FILE_OK)
216 return;
217
218 if (app_list.get()) {
219 webapps_registry_->UpdateFromAppList(*app_list);
220 }
221 }
222
223 void ChangeListLoader::OnGetResourceList( 402 void ChangeListLoader::OnGetResourceList(
224 ScopedVector<ChangeList> change_lists, 403 ScopedVector<ChangeList> change_lists,
225 const LoadFeedListCallback& callback, 404 const LoadFeedListCallback& callback,
226 base::TimeTicks start_time, 405 base::TimeTicks start_time,
227 google_apis::GDataErrorCode status, 406 google_apis::GDataErrorCode status,
228 scoped_ptr<google_apis::ResourceList> resource_list) { 407 scoped_ptr<google_apis::ResourceList> resource_list) {
229 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 408 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
230 DCHECK(!callback.is_null()); 409 DCHECK(!callback.is_null());
231 410
232 // Looks the UMA stats we take here is useless as many methods use this 411 // Looks the UMA stats we take here is useless as many methods use this
(...skipping 28 matching lines...) Expand all
261 } 440 }
262 441
263 // This UMA stats looks also different from what we want. crbug.com/229407 442 // This UMA stats looks also different from what we want. crbug.com/229407
264 UMA_HISTOGRAM_TIMES("Drive.EntireFeedLoadTime", 443 UMA_HISTOGRAM_TIMES("Drive.EntireFeedLoadTime",
265 base::TimeTicks::Now() - start_time); 444 base::TimeTicks::Now() - start_time);
266 445
267 // Run the callback so the client can process the retrieved feeds. 446 // Run the callback so the client can process the retrieved feeds.
268 callback.Run(change_lists.Pass(), DRIVE_FILE_OK); 447 callback.Run(change_lists.Pass(), DRIVE_FILE_OK);
269 } 448 }
270 449
271 void ChangeListLoader::LoadDirectoryFromServer( 450 void ChangeListLoader::UpdateMetadataFromFeedAfterLoadFromServer(
272 const std::string& directory_resource_id, 451 scoped_ptr<google_apis::AboutResource> about_resource,
273 const FileOperationCallback& callback) { 452 bool is_delta_feed,
453 ScopedVector<ChangeList> change_lists,
454 DriveFileError error) {
274 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 455 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
275 DCHECK(!callback.is_null());
276 456
277 // First fetch the latest changestamp to see if this directory needs to be 457 if (error != DRIVE_FILE_OK) {
278 // updated. 458 OnChangeListLoadComplete(error);
279 scheduler_->GetAboutResource( 459 return;
280 base::Bind( 460 }
281 &ChangeListLoader::LoadDirectoryFromServerAfterGetAbout, 461
282 weak_ptr_factory_.GetWeakPtr(), 462 UpdateFromFeed(about_resource.Pass(),
283 directory_resource_id, 463 change_lists.Pass(),
284 callback)); 464 is_delta_feed,
465 base::Bind(&ChangeListLoader::OnUpdateFromFeed,
466 weak_ptr_factory_.GetWeakPtr()));
467 }
468
469 void ChangeListLoader::OnUpdateFromFeed() {
470 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
471
472 OnChangeListLoadComplete(DRIVE_FILE_OK);
473
474 FOR_EACH_OBSERVER(ChangeListLoaderObserver,
475 observers_,
476 OnFeedFromServerLoaded());
285 } 477 }
286 478
287 void ChangeListLoader::LoadDirectoryFromServerAfterGetAbout( 479 void ChangeListLoader::LoadDirectoryFromServerAfterGetAbout(
288 const std::string& directory_resource_id, 480 const std::string& directory_resource_id,
289 const FileOperationCallback& callback, 481 const FileOperationCallback& callback,
290 google_apis::GDataErrorCode status, 482 google_apis::GDataErrorCode status,
291 scoped_ptr<google_apis::AboutResource> about_resource) { 483 scoped_ptr<google_apis::AboutResource> about_resource) {
292 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 484 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
293 DCHECK(!callback.is_null()); 485 DCHECK(!callback.is_null());
294 486
295 if (util::GDataToDriveFileError(status) == DRIVE_FILE_OK) { 487 if (util::GDataToDriveFileError(status) == DRIVE_FILE_OK) {
296 DCHECK(about_resource); 488 DCHECK(about_resource);
297 last_known_remote_changestamp_ = about_resource->largest_change_id(); 489 last_known_remote_changestamp_ = about_resource->largest_change_id();
298 } 490 }
299 491
300 const DirectoryFetchInfo directory_fetch_info( 492 const DirectoryFetchInfo directory_fetch_info(
301 directory_resource_id, 493 directory_resource_id,
302 last_known_remote_changestamp_); 494 last_known_remote_changestamp_);
303 DoLoadDirectoryFromServer(directory_fetch_info, callback); 495 DoLoadDirectoryFromServer(directory_fetch_info, callback);
304 } 496 }
305 497
498 void ChangeListLoader::CheckChangestampAndLoadDirectoryIfNeeed(
499 const DirectoryFetchInfo& directory_fetch_info,
500 int64 local_changestamp,
501 const FileOperationCallback& callback) {
502 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
503 DCHECK(!directory_fetch_info.empty());
504
505 int64 directory_changestamp = std::max(directory_fetch_info.changestamp(),
506 local_changestamp);
507
508 // If the directory's changestamp is up-to-date, just schedule to run the
509 // callback, as there is no need to fetch the directory.
510 // Note that |last_known_remote_changestamp_| is 0 when it is not received
511 // yet. In that case we conservatively assume that we need to fetch.
512 if (last_known_remote_changestamp_ > 0 &&
513 directory_changestamp >= last_known_remote_changestamp_) {
514 callback.Run(DRIVE_FILE_OK);
515 return;
516 }
517
518 DVLOG(1) << "Fast-fetching directory: " << directory_fetch_info.ToString()
519 << "; remote_changestamp: " << last_known_remote_changestamp_;
520
521 // Start fetching the directory content, and mark it with the changestamp
522 // |last_known_remote_changestamp_|.
523 DirectoryFetchInfo new_directory_fetch_info(
524 directory_fetch_info.resource_id(),
525 std::max(directory_changestamp, last_known_remote_changestamp_));
526 DoLoadDirectoryFromServer(new_directory_fetch_info, callback);
527 }
528
306 void ChangeListLoader::DoLoadDirectoryFromServer( 529 void ChangeListLoader::DoLoadDirectoryFromServer(
307 const DirectoryFetchInfo& directory_fetch_info, 530 const DirectoryFetchInfo& directory_fetch_info,
308 const FileOperationCallback& callback) { 531 const FileOperationCallback& callback) {
309 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 532 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
310 DCHECK(!callback.is_null()); 533 DCHECK(!callback.is_null());
311 DCHECK(!directory_fetch_info.empty()); 534 DCHECK(!directory_fetch_info.empty());
312 DVLOG(1) << "Start loading directory: " << directory_fetch_info.ToString(); 535 DVLOG(1) << "Start loading directory: " << directory_fetch_info.ToString();
313 536
314 if (directory_fetch_info.resource_id() == 537 if (directory_fetch_info.resource_id() ==
315 util::kDriveOtherDirSpecialResourceId) { 538 util::kDriveOtherDirSpecialResourceId) {
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after
452 675
453 DVLOG(1) << "Directory loaded: " << directory_fetch_info.ToString(); 676 DVLOG(1) << "Directory loaded: " << directory_fetch_info.ToString();
454 callback.Run(error); 677 callback.Run(error);
455 // Also notify the observers. 678 // Also notify the observers.
456 if (error == DRIVE_FILE_OK) { 679 if (error == DRIVE_FILE_OK) {
457 FOR_EACH_OBSERVER(ChangeListLoaderObserver, observers_, 680 FOR_EACH_OBSERVER(ChangeListLoaderObserver, observers_,
458 OnDirectoryChanged(directory_path)); 681 OnDirectoryChanged(directory_path));
459 } 682 }
460 } 683 }
461 684
462 void ChangeListLoader::SearchFromServer( 685 void ChangeListLoader::OnGetAppList(google_apis::GDataErrorCode status,
463 const std::string& search_query, 686 scoped_ptr<google_apis::AppList> app_list) {
464 const GURL& next_feed, 687 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
465 const LoadFeedListCallback& callback) { 688
689 DriveFileError error = util::GDataToDriveFileError(status);
690 if (error != DRIVE_FILE_OK)
691 return;
692
693 if (app_list.get())
694 webapps_registry_->UpdateFromAppList(*app_list);
695 }
696
697 void ChangeListLoader::SearchFromServerAfterGetResourceList(
698 const LoadFeedListCallback& callback,
699 google_apis::GDataErrorCode status,
700 scoped_ptr<google_apis::ResourceList> resource_list) {
701 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
466 DCHECK(!callback.is_null()); 702 DCHECK(!callback.is_null());
467 703
468 if (next_feed.is_empty()) { 704 DriveFileError error = util::GDataToDriveFileError(status);
469 // This is first request for the |search_query|.
470 scheduler_->Search(
471 search_query,
472 base::Bind(&ChangeListLoader::SearchFromServerAfterGetResourceList,
473 weak_ptr_factory_.GetWeakPtr(), callback));
474 } else {
475 // There is the remaining result so fetch it.
476 scheduler_->ContinueGetResourceList(
477 next_feed,
478 base::Bind(&ChangeListLoader::SearchFromServerAfterGetResourceList,
479 weak_ptr_factory_.GetWeakPtr(), callback));
480 }
481 }
482
483 void ChangeListLoader::UpdateMetadataFromFeedAfterLoadFromServer(
484 scoped_ptr<google_apis::AboutResource> about_resource,
485 bool is_delta_feed,
486 ScopedVector<ChangeList> change_lists,
487 DriveFileError error) {
488 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
489
490 if (error != DRIVE_FILE_OK) { 705 if (error != DRIVE_FILE_OK) {
491 OnChangeListLoadComplete(error); 706 callback.Run(ScopedVector<ChangeList>(), error);
492 return; 707 return;
493 } 708 }
494 709
495 UpdateFromFeed(about_resource.Pass(), 710 DCHECK(resource_list);
496 change_lists.Pass(),
497 is_delta_feed,
498 base::Bind(&ChangeListLoader::OnUpdateFromFeed,
499 weak_ptr_factory_.GetWeakPtr()));
500 }
501 711
502 void ChangeListLoader::LoadIfNeeded( 712 ScopedVector<ChangeList> change_lists;
503 const DirectoryFetchInfo& directory_fetch_info, 713 change_lists.push_back(new ChangeList(*resource_list));
504 const FileOperationCallback& callback) { 714 callback.Run(change_lists.Pass(), DRIVE_FILE_OK);
505 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
506 DCHECK(!callback.is_null());
507
508 // If feed has already been loaded, for normal feed fetch (= empty
509 // directory_fetch_info), we have nothing to do. For "fast fetch", we need to
510 // schedule a fetching if a feed refresh is currently running, because we
511 // don't want to wait a possibly large delta feed to arrive.
512 if (loaded_ && (directory_fetch_info.empty() || !IsRefreshing())) {
513 base::MessageLoopProxy::current()->PostTask(
514 FROM_HERE,
515 base::Bind(callback, DRIVE_FILE_OK));
516 return;
517 }
518 Load(directory_fetch_info, callback);
519 }
520
521 void ChangeListLoader::Load(const DirectoryFetchInfo& directory_fetch_info,
522 const FileOperationCallback& callback) {
523 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
524 DCHECK(!callback.is_null());
525
526 // Check if this is the first time this ChangeListLoader do loading.
527 // Note: IsRefreshing() depends on pending_load_callback_ so check in advance.
528 const bool is_initial_load = (!loaded_ && !IsRefreshing());
529
530 // Register the callback function to be called when it is loaded.
531 const std::string& resource_id = directory_fetch_info.resource_id();
532 pending_load_callback_[resource_id].push_back(callback);
533
534 // If loading task for |resource_id| is already running, do nothing.
535 if (pending_load_callback_[resource_id].size() > 1)
536 return;
537
538 // For initial loading, even for directory fetching, we do load the full
539 // feed from the server to sync up. So we register a dummy callback to
540 // indicate that update for full hierarchy is running.
541 if (is_initial_load && !resource_id.empty()) {
542 pending_load_callback_[""].push_back(
543 base::Bind(&util::EmptyFileOperationCallback));
544 }
545
546 // Check the current status of local metadata, and start loading if needed.
547 resource_metadata_->GetLargestChangestamp(
548 base::Bind(is_initial_load ? &ChangeListLoader::DoInitialLoad
549 : &ChangeListLoader::DoUpdateLoad,
550 weak_ptr_factory_.GetWeakPtr(),
551 directory_fetch_info));
552 }
553
554 void ChangeListLoader::DoInitialLoad(
555 const DirectoryFetchInfo& directory_fetch_info,
556 int64 local_changestamp) {
557 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
558
559 if (local_changestamp > 0) {
560 // The local data is usable. Flush callbacks to tell loading was successful.
561 OnChangeListLoadComplete(DRIVE_FILE_OK);
562
563 // Continues to load from server in background.
564 // Put dummy callbacks to indicate that fetching is still continuing.
565 pending_load_callback_[directory_fetch_info.resource_id()].push_back(
566 base::Bind(&util::EmptyFileOperationCallback));
567 if (!directory_fetch_info.empty()) {
568 pending_load_callback_[""].push_back(
569 base::Bind(&util::EmptyFileOperationCallback));
570 }
571 }
572 LoadFromServerIfNeeded(directory_fetch_info, local_changestamp);
573 }
574
575 void ChangeListLoader::DoUpdateLoad(
576 const DirectoryFetchInfo& directory_fetch_info,
577 int64 local_changestamp) {
578 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
579
580 if (directory_fetch_info.empty()) {
581 LoadFromServerIfNeeded(directory_fetch_info, local_changestamp);
582 } else {
583 // Note: CheckChangestampAndLoadDirectoryIfNeeded regards
584 // last_know_remote_changestamp_ as the remote changestamp. To be precise,
585 // we need to call GetAboutResource() here, as we do in other places like
586 // LoadFromServerIfNeeded or LoadFromDirectory. However,
587 // - It is costly to do GetAboutResource HTTP request every time.
588 // - The chance using an old value is small; it only happens when
589 // LoadIfNeeded is called during one GetAboutResource roundtrip time
590 // of a feed fetching.
591 // - Even if the value is old, it just marks the directory as older. It may
592 // trigger one future unnecessary re-fetch, but it'll never lose data.
593 CheckChangestampAndLoadDirectoryIfNeeed(
594 directory_fetch_info,
595 local_changestamp,
596 base::Bind(&ChangeListLoader::OnDirectoryLoadComplete,
597 weak_ptr_factory_.GetWeakPtr(),
598 directory_fetch_info));
599 }
600 }
601
602 void ChangeListLoader::CheckForUpdates(const FileOperationCallback& callback) {
603 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
604 DCHECK(!callback.is_null());
605
606 if (loaded_ && !IsRefreshing())
607 Load(DirectoryFetchInfo(), callback);
608 }
609
610 void ChangeListLoader::UpdateFromFeed(
611 scoped_ptr<google_apis::AboutResource> about_resource,
612 ScopedVector<ChangeList> change_lists,
613 bool is_delta_feed,
614 const base::Closure& update_finished_callback) {
615 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
616 DCHECK(!update_finished_callback.is_null());
617
618 change_list_processor_.reset(new ChangeListProcessor(resource_metadata_));
619 // Don't send directory content change notification while performing
620 // the initial content retrieval.
621 const bool should_notify_changed_directories = is_delta_feed;
622
623 change_list_processor_->ApplyFeeds(
624 about_resource.Pass(),
625 change_lists.Pass(),
626 is_delta_feed,
627 base::Bind(&ChangeListLoader::NotifyDirectoryChangedAfterApplyFeed,
628 weak_ptr_factory_.GetWeakPtr(),
629 should_notify_changed_directories,
630 update_finished_callback));
631 }
632
633 void ChangeListLoader::CheckChangestampAndLoadDirectoryIfNeeed(
634 const DirectoryFetchInfo& directory_fetch_info,
635 int64 local_changestamp,
636 const FileOperationCallback& callback) {
637 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
638 DCHECK(!directory_fetch_info.empty());
639
640 int64 directory_changestamp = std::max(directory_fetch_info.changestamp(),
641 local_changestamp);
642
643 // If the directory's changestamp is up-to-date, just schedule to run the
644 // callback, as there is no need to fetch the directory.
645 // Note that |last_known_remote_changestamp_| is 0 when it is not received
646 // yet. In that case we conservatively assume that we need to fetch.
647 if (last_known_remote_changestamp_ > 0 &&
648 directory_changestamp >= last_known_remote_changestamp_) {
649 callback.Run(DRIVE_FILE_OK);
650 return;
651 }
652
653 DVLOG(1) << "Fast-fetching directory: " << directory_fetch_info.ToString()
654 << "; remote_changestamp: " << last_known_remote_changestamp_;
655
656 // Start fetching the directory content, and mark it with the changestamp
657 // |last_known_remote_changestamp_|.
658 DirectoryFetchInfo new_directory_fetch_info(
659 directory_fetch_info.resource_id(),
660 std::max(directory_changestamp, last_known_remote_changestamp_));
661 DoLoadDirectoryFromServer(new_directory_fetch_info, callback);
662 } 715 }
663 716
664 void ChangeListLoader::NotifyDirectoryChangedAfterApplyFeed( 717 void ChangeListLoader::NotifyDirectoryChangedAfterApplyFeed(
665 bool should_notify_changed_directories, 718 bool should_notify_changed_directories,
666 const base::Closure& update_finished_callback) { 719 const base::Closure& callback) {
667 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 720 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
668 DCHECK(change_list_processor_.get()); 721 DCHECK(change_list_processor_.get());
669 DCHECK(!update_finished_callback.is_null()); 722 DCHECK(!callback.is_null());
670 723
671 if (should_notify_changed_directories) { 724 if (should_notify_changed_directories) {
672 for (std::set<base::FilePath>::iterator dir_iter = 725 for (std::set<base::FilePath>::iterator dir_iter =
673 change_list_processor_->changed_dirs().begin(); 726 change_list_processor_->changed_dirs().begin();
674 dir_iter != change_list_processor_->changed_dirs().end(); 727 dir_iter != change_list_processor_->changed_dirs().end();
675 ++dir_iter) { 728 ++dir_iter) {
676 FOR_EACH_OBSERVER(ChangeListLoaderObserver, observers_, 729 FOR_EACH_OBSERVER(ChangeListLoaderObserver, observers_,
677 OnDirectoryChanged(*dir_iter)); 730 OnDirectoryChanged(*dir_iter));
678 } 731 }
679 } 732 }
680 733
681 update_finished_callback.Run(); 734 callback.Run();
682 735
683 // Cannot delete change_list_processor_ yet because we are in 736 // Cannot delete change_list_processor_ yet because we are in
684 // on_complete_callback_, which is owned by change_list_processor_. 737 // on_complete_callback_, which is owned by change_list_processor_.
685 } 738 }
686 739
687 void ChangeListLoader::OnUpdateFromFeed() {
688 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
689
690 OnChangeListLoadComplete(DRIVE_FILE_OK);
691
692 FOR_EACH_OBSERVER(ChangeListLoaderObserver,
693 observers_,
694 OnFeedFromServerLoaded());
695 }
696
697 void ChangeListLoader::OnChangeListLoadComplete(DriveFileError error) {
698 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
699
700 if (!loaded_ && error == DRIVE_FILE_OK) {
701 loaded_ = true;
702 FOR_EACH_OBSERVER(ChangeListLoaderObserver,
703 observers_,
704 OnInitialFeedLoaded());
705 }
706
707 for (LoadCallbackMap::iterator it = pending_load_callback_.begin();
708 it != pending_load_callback_.end(); ++it) {
709 const std::vector<FileOperationCallback>& callbacks = it->second;
710 for (size_t i = 0; i < callbacks.size(); ++i) {
711 base::MessageLoopProxy::current()->PostTask(
712 FROM_HERE,
713 base::Bind(callbacks[i], error));
714 }
715 }
716 pending_load_callback_.clear();
717 }
718
719 void ChangeListLoader::OnDirectoryLoadComplete(
720 const DirectoryFetchInfo& directory_fetch_info,
721 DriveFileError error) {
722 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
723
724 DVLOG_IF(1, error == DRIVE_FILE_OK) << "Fast-fetch was successful: "
725 << directory_fetch_info.ToString();
726
727 const std::string& resource_id = directory_fetch_info.resource_id();
728 LoadCallbackMap::iterator it = pending_load_callback_.find(resource_id);
729 if (it != pending_load_callback_.end()) {
730 DVLOG(1) << "Running callback for " << resource_id;
731 const std::vector<FileOperationCallback>& callbacks = it->second;
732 for (size_t i = 0; i < callbacks.size(); ++i) {
733 base::MessageLoopProxy::current()->PostTask(
734 FROM_HERE,
735 base::Bind(callbacks[i], error));
736 }
737 pending_load_callback_.erase(it);
738 }
739 }
740
741 } // namespace drive 740 } // namespace drive
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698