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

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

Issue 10834170: gdata: Move GDataWapiFeedLoader to a set of new files (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: add missing files... Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/chromeos/gdata/gdata_wapi_feed_loader.h"
6
7 #include "base/command_line.h"
8 #include "base/file_util.h"
9 #include "base/json/json_reader.h"
10 #include "base/json/json_writer.h"
11 #include "base/message_loop.h"
12 #include "base/metrics/histogram.h"
13 #include "base/threading/sequenced_worker_pool.h"
14 #include "chrome/browser/chromeos/gdata/drive_webapps_registry.h"
15 #include "chrome/browser/chromeos/gdata/gdata_cache.h"
16 #include "chrome/browser/chromeos/gdata/gdata_documents_service.h"
17 #include "chrome/browser/chromeos/gdata/gdata_util.h"
18 #include "chrome/browser/chromeos/gdata/gdata_wapi_feed_processor.h"
19 #include "chrome/common/chrome_switches.h"
20 #include "content/public/browser/browser_thread.h"
21
22 using content::BrowserThread;
23
24 namespace gdata {
25
26 namespace {
27
28 const FilePath::CharType kAccountMetadataFile[] =
29 FILE_PATH_LITERAL("account_metadata.json");
30 const FilePath::CharType kFilesystemProtoFile[] =
31 FILE_PATH_LITERAL("file_system.pb");
32 const FilePath::CharType kResourceMetadataDBFile[] =
33 FILE_PATH_LITERAL("resource_metadata.db");
34
35 // Update the fetch progress UI per every this number of feeds.
36 const int kFetchUiUpdateStep = 10;
37
38 // Schedule for dumping root file system proto buffers to disk depending its
39 // total protobuffer size in MB.
40 typedef struct {
41 double size;
42 int timeout;
43 } SerializationTimetable;
44
45 SerializationTimetable kSerializeTimetable[] = {
46 #ifndef NDEBUG
47 {0.5, 0}, // Less than 0.5MB, dump immediately.
48 {-1, 1}, // Any size, dump if older than 1 minute.
49 #else
50 {0.5, 0}, // Less than 0.5MB, dump immediately.
51 {1.0, 15}, // Less than 1.0MB, dump after 15 minutes.
52 {2.0, 30},
53 {4.0, 60},
54 {-1, 120}, // Any size, dump if older than 120 minutes.
55 #endif
56 };
57
58 // Loads the file at |path| into the string |serialized_proto| on a blocking
59 // thread.
60 void LoadProtoOnBlockingPool(const FilePath& path,
61 LoadRootFeedParams* params) {
62 base::PlatformFileInfo info;
63 if (!file_util::GetFileInfo(path, &info)) {
64 params->load_error = GDATA_FILE_ERROR_NOT_FOUND;
65 return;
66 }
67 params->last_modified = info.last_modified;
68 if (!file_util::ReadFileToString(path, &params->proto)) {
69 LOG(WARNING) << "Proto file not found at " << path.value();
70 params->load_error = GDATA_FILE_ERROR_NOT_FOUND;
71 return;
72 }
73 params->load_error = GDATA_FILE_OK;
74 }
75
76 // Saves json file content content in |feed| to |file_pathname| on blocking
77 // pool. Used for debugging.
78 void SaveFeedOnBlockingPoolForDebugging(
79 const FilePath& file_path,
80 scoped_ptr<base::Value> feed) {
81 std::string json;
82 base::JSONWriter::WriteWithOptions(feed.get(),
83 base::JSONWriter::OPTIONS_PRETTY_PRINT,
84 &json);
85
86 int file_size = static_cast<int>(json.length());
87 if (file_util::WriteFile(file_path, json.data(), file_size) != file_size) {
88 LOG(WARNING) << "GData metadata file can't be stored at "
89 << file_path.value();
90 if (!file_util::Delete(file_path, true)) {
91 LOG(WARNING) << "GData metadata file can't be deleted at "
92 << file_path.value();
93 return;
94 }
95 }
96 }
97
98 // Returns true if file system is due to be serialized on disk based on it
99 // |serialized_size| and |last_serialized| timestamp.
100 bool ShouldSerializeFileSystemNow(size_t serialized_size,
101 const base::Time& last_serialized) {
102 const double size_in_mb = serialized_size / 1048576.0;
103 const int last_proto_dump_in_min =
104 (base::Time::Now() - last_serialized).InMinutes();
105 for (size_t i = 0; i < arraysize(kSerializeTimetable); i++) {
106 if ((size_in_mb < kSerializeTimetable[i].size ||
107 kSerializeTimetable[i].size == -1) &&
108 last_proto_dump_in_min >= kSerializeTimetable[i].timeout) {
109 return true;
110 }
111 }
112 return false;
113 }
114
115 // Saves the string |serialized_proto| to a file at |path| on a blocking thread.
116 void SaveProtoOnBlockingPool(const FilePath& path,
117 scoped_ptr<std::string> serialized_proto) {
118 const int file_size = static_cast<int>(serialized_proto->length());
119 if (file_util::WriteFile(path, serialized_proto->data(), file_size) !=
120 file_size) {
121 LOG(WARNING) << "GData proto file can't be stored at "
122 << path.value();
123 if (!file_util::Delete(path, true)) {
124 LOG(WARNING) << "GData proto file can't be deleted at "
125 << path.value();
126 }
127 }
128 }
129
130 bool UseLevelDB() {
131 return CommandLine::ForCurrentProcess()->HasSwitch(
132 switches::kUseLevelDBForGData);
133 }
134
135 } // namespace
136
137 GetDocumentsParams::GetDocumentsParams(
138 int start_changestamp,
139 int root_feed_changestamp,
140 std::vector<DocumentFeed*>* feed_list,
141 bool should_fetch_multiple_feeds,
142 const FilePath& search_file_path,
143 const std::string& search_query,
144 const std::string& directory_resource_id,
145 const FindEntryCallback& callback,
146 GetDocumentsUiState* ui_state)
147 : start_changestamp(start_changestamp),
148 root_feed_changestamp(root_feed_changestamp),
149 feed_list(feed_list),
150 should_fetch_multiple_feeds(should_fetch_multiple_feeds),
151 search_file_path(search_file_path),
152 search_query(search_query),
153 directory_resource_id(directory_resource_id),
154 callback(callback),
155 ui_state(ui_state) {
156 }
157
158 GetDocumentsParams::~GetDocumentsParams() {
159 STLDeleteElements(feed_list.get());
160 }
161
162 // Defines set of parameters sent to callback OnNotifyDocumentFeedFetched().
163 // This is a trick to update the number of fetched documents frequently on
164 // UI. Due to performance reason, we need to fetch a number of files at
165 // a time. However, it'll take long time, and a user has no way to know
166 // the current update state. In order to make users confortable,
167 // we increment the number of fetched documents with more frequent but smaller
168 // steps than actual fetching.
169 struct GetDocumentsUiState {
170 explicit GetDocumentsUiState(base::TimeTicks start_time)
171 : num_fetched_documents(0),
172 num_showing_documents(0),
173 start_time(start_time),
174 weak_ptr_factory(this) {
175 }
176
177 // The number of fetched documents.
178 int num_fetched_documents;
179
180 // The number documents shown on UI.
181 int num_showing_documents;
182
183 // When the UI update has started.
184 base::TimeTicks start_time;
185
186 // Time elapsed since the feed fetching was started.
187 base::TimeDelta feed_fetching_elapsed_time;
188
189 base::WeakPtrFactory<GetDocumentsUiState> weak_ptr_factory;
190 };
191
192 GDataWapiFeedLoader::GDataWapiFeedLoader(
193 GDataDirectoryService* directory_service,
194 DocumentsServiceInterface* documents_service,
195 DriveWebAppsRegistryInterface* webapps_registry,
196 GDataCache* cache,
197 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner)
198 : directory_service_(directory_service),
199 documents_service_(documents_service),
200 webapps_registry_(webapps_registry),
201 cache_(cache),
202 blocking_task_runner_(blocking_task_runner),
203 weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
204 }
205
206 GDataWapiFeedLoader::~GDataWapiFeedLoader() {
207 }
208
209 void GDataWapiFeedLoader::AddObserver(Observer* observer) {
210 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
211 observers_.AddObserver(observer);
212 }
213
214 void GDataWapiFeedLoader::RemoveObserver(Observer* observer) {
215 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
216 observers_.RemoveObserver(observer);
217 }
218
219 void GDataWapiFeedLoader::ReloadFromServerIfNeeded(
220 ContentOrigin initial_origin,
221 int local_changestamp,
222 const FilePath& search_file_path,
223 const FindEntryCallback& callback) {
224 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
225
226 DVLOG(1) << "ReloadFeedFromServerIfNeeded local_changestamp="
227 << local_changestamp << ", initial_origin=" << initial_origin;
228
229 // First fetch the latest changestamp to see if there were any new changes
230 // there at all.
231 documents_service_->GetAccountMetadata(
232 base::Bind(&GDataWapiFeedLoader::OnGetAccountMetadata,
233 weak_ptr_factory_.GetWeakPtr(),
234 initial_origin,
235 local_changestamp,
236 search_file_path,
237 callback));
238 }
239
240 void GDataWapiFeedLoader::OnGetAccountMetadata(
241 ContentOrigin initial_origin,
242 int local_changestamp,
243 const FilePath& search_file_path,
244 const FindEntryCallback& callback,
245 GDataErrorCode status,
246 scoped_ptr<base::Value> feed_data) {
247 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
248
249 GDataFileError error = util::GDataToGDataFileError(status);
250 if (error != GDATA_FILE_OK) {
251 // Get changes starting from the next changestamp from what we have locally.
252 LoadFromServer(initial_origin,
253 local_changestamp + 1, 0,
254 true, /* should_fetch_multiple_feeds */
255 search_file_path,
256 std::string() /* no search query */,
257 GURL(), /* feed not explicitly set */
258 std::string() /* no directory resource ID */,
259 callback,
260 base::Bind(&GDataWapiFeedLoader::OnFeedFromServerLoaded,
261 weak_ptr_factory_.GetWeakPtr()));
262 return;
263 }
264
265 scoped_ptr<AccountMetadataFeed> account_metadata;
266 if (feed_data.get()) {
267 account_metadata = AccountMetadataFeed::CreateFrom(*feed_data);
268 #ifndef NDEBUG
269 // Save account metadata feed for analysis.
270 const FilePath path =
271 cache_->GetCacheDirectoryPath(GDataCache::CACHE_TYPE_META).Append(
272 kAccountMetadataFile);
273 util::PostBlockingPoolSequencedTask(
274 FROM_HERE,
275 blocking_task_runner_,
276 base::Bind(&SaveFeedOnBlockingPoolForDebugging,
277 path, base::Passed(&feed_data)));
278 #endif
279 }
280
281 if (!account_metadata.get()) {
282 LoadFromServer(initial_origin,
283 local_changestamp + 1, 0,
284 true, /* should_fetch_multiple_feeds */
285 search_file_path,
286 std::string() /* no search query */,
287 GURL(), /* feed not explicitly set */
288 std::string() /* no directory resource ID */,
289 callback,
290 base::Bind(&GDataWapiFeedLoader::OnFeedFromServerLoaded,
291 weak_ptr_factory_.GetWeakPtr()));
292 return;
293 }
294
295 webapps_registry_->UpdateFromFeed(account_metadata.get());
296
297 bool changes_detected = true;
298 if (local_changestamp >= account_metadata->largest_changestamp()) {
299 if (local_changestamp > account_metadata->largest_changestamp()) {
300 LOG(WARNING) << "Cached client feed is fresher than server, client = "
301 << local_changestamp
302 << ", server = "
303 << account_metadata->largest_changestamp();
304 }
305 // If our cache holds the latest state from the server, change the
306 // state to FROM_SERVER.
307 directory_service_->set_origin(
308 initial_origin == FROM_CACHE ? FROM_SERVER : initial_origin);
309 changes_detected = false;
310 }
311
312 // No changes detected, continue with search as planned.
313 if (!changes_detected) {
314 if (!callback.is_null()) {
315 directory_service_->FindEntryByPathAndRunSync(search_file_path,
316 callback);
317 }
318 return;
319 }
320
321 // Load changes from the server.
322 LoadFromServer(initial_origin,
323 local_changestamp > 0 ? local_changestamp + 1 : 0,
324 account_metadata->largest_changestamp(),
325 true, /* should_fetch_multiple_feeds */
326 search_file_path,
327 std::string() /* no search query */,
328 GURL(), /* feed not explicitly set */
329 std::string() /* no directory resource ID */,
330 callback,
331 base::Bind(&GDataWapiFeedLoader::OnFeedFromServerLoaded,
332 weak_ptr_factory_.GetWeakPtr()));
333 }
334
335 void GDataWapiFeedLoader::LoadFromServer(
336 ContentOrigin initial_origin,
337 int start_changestamp,
338 int root_feed_changestamp,
339 bool should_fetch_multiple_feeds,
340 const FilePath& search_file_path,
341 const std::string& search_query,
342 const GURL& feed_to_load,
343 const std::string& directory_resource_id,
344 const FindEntryCallback& entry_found_callback,
345 const LoadDocumentFeedCallback& feed_load_callback) {
346 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
347
348 // |feed_list| will contain the list of all collected feed updates that
349 // we will receive through calls of DocumentsService::GetDocuments().
350 scoped_ptr<std::vector<DocumentFeed*> > feed_list(
351 new std::vector<DocumentFeed*>);
352 const base::TimeTicks start_time = base::TimeTicks::Now();
353 documents_service_->GetDocuments(
354 feed_to_load,
355 start_changestamp,
356 search_query,
357 directory_resource_id,
358 base::Bind(&GDataWapiFeedLoader::OnGetDocuments,
359 weak_ptr_factory_.GetWeakPtr(),
360 initial_origin,
361 feed_load_callback,
362 base::Owned(new GetDocumentsParams(start_changestamp,
363 root_feed_changestamp,
364 feed_list.release(),
365 should_fetch_multiple_feeds,
366 search_file_path,
367 search_query,
368 directory_resource_id,
369 entry_found_callback,
370 NULL)),
371 start_time));
372 }
373
374 void GDataWapiFeedLoader::OnFeedFromServerLoaded(GetDocumentsParams* params,
375 GDataFileError error) {
376 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
377
378 if (error != GDATA_FILE_OK) {
379 if (!params->callback.is_null())
380 params->callback.Run(error, NULL);
381 return;
382 }
383
384 error = UpdateFromFeed(*params->feed_list,
385 params->start_changestamp,
386 params->root_feed_changestamp);
387
388 if (error != GDATA_FILE_OK) {
389 if (!params->callback.is_null())
390 params->callback.Run(error, NULL);
391
392 return;
393 }
394
395 // Save file system metadata to disk.
396 SaveFileSystem();
397
398 // If we had someone to report this too, then this retrieval was done in a
399 // context of search... so continue search.
400 if (!params->callback.is_null()) {
401 directory_service_->FindEntryByPathAndRunSync(params->search_file_path,
402 params->callback);
403 }
404
405 FOR_EACH_OBSERVER(Observer, observers_, OnFeedFromServerLoaded());
406 }
407
408 void GDataWapiFeedLoader::OnGetDocuments(
409 ContentOrigin initial_origin,
410 const LoadDocumentFeedCallback& callback,
411 GetDocumentsParams* params,
412 base::TimeTicks start_time,
413 GDataErrorCode status,
414 scoped_ptr<base::Value> data) {
415 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
416
417 if (params->feed_list->empty()) {
418 UMA_HISTOGRAM_TIMES("Gdata.InitialFeedLoadTime",
419 base::TimeTicks::Now() - start_time);
420 }
421
422 GDataFileError error = util::GDataToGDataFileError(status);
423 if (error == GDATA_FILE_OK &&
424 (!data.get() || data->GetType() != Value::TYPE_DICTIONARY)) {
425 error = GDATA_FILE_ERROR_FAILED;
426 }
427
428 if (error != GDATA_FILE_OK) {
429 directory_service_->set_origin(initial_origin);
430
431 if (!callback.is_null())
432 callback.Run(params, error);
433
434 return;
435 }
436
437 GURL next_feed_url;
438 scoped_ptr<DocumentFeed> current_feed(DocumentFeed::ExtractAndParse(*data));
439 if (!current_feed.get()) {
440 if (!callback.is_null()) {
441 callback.Run(params, GDATA_FILE_ERROR_FAILED);
442 }
443
444 return;
445 }
446 const bool has_next_feed_url = current_feed->GetNextFeedURL(&next_feed_url);
447
448 #ifndef NDEBUG
449 // Save initial root feed for analysis.
450 std::string file_name =
451 base::StringPrintf("DEBUG_feed_%d.json",
452 params->start_changestamp);
453 util::PostBlockingPoolSequencedTask(
454 FROM_HERE,
455 blocking_task_runner_,
456 base::Bind(&SaveFeedOnBlockingPoolForDebugging,
457 cache_->GetCacheDirectoryPath(
458 GDataCache::CACHE_TYPE_META).Append(file_name),
459 base::Passed(&data)));
460 #endif
461
462 // Add the current feed to the list of collected feeds for this directory.
463 params->feed_list->push_back(current_feed.release());
464
465 // Compute and notify the number of entries fetched so far.
466 int num_accumulated_entries = 0;
467 for (size_t i = 0; i < params->feed_list->size(); ++i)
468 num_accumulated_entries += params->feed_list->at(i)->entries().size();
469
470 // Check if we need to collect more data to complete the directory list.
471 if (params->should_fetch_multiple_feeds && has_next_feed_url &&
472 !next_feed_url.is_empty()) {
473 // Post an UI update event to make the UI smoother.
474 GetDocumentsUiState* ui_state = params->ui_state.get();
475 if (ui_state == NULL) {
476 ui_state = new GetDocumentsUiState(base::TimeTicks::Now());
477 params->ui_state.reset(ui_state);
478 }
479 DCHECK(ui_state);
480
481 if ((ui_state->num_fetched_documents - ui_state->num_showing_documents)
482 < kFetchUiUpdateStep) {
483 // Currently the UI update is stopped. Start UI periodic callback.
484 MessageLoop::current()->PostTask(
485 FROM_HERE,
486 base::Bind(&GDataWapiFeedLoader::OnNotifyDocumentFeedFetched,
487 weak_ptr_factory_.GetWeakPtr(),
488 ui_state->weak_ptr_factory.GetWeakPtr()));
489 }
490 ui_state->num_fetched_documents = num_accumulated_entries;
491 ui_state->feed_fetching_elapsed_time = base::TimeTicks::Now() - start_time;
492
493 // Kick of the remaining part of the feeds.
494 documents_service_->GetDocuments(
495 next_feed_url,
496 params->start_changestamp,
497 params->search_query,
498 params->directory_resource_id,
499 base::Bind(&GDataWapiFeedLoader::OnGetDocuments,
500 weak_ptr_factory_.GetWeakPtr(),
501 initial_origin,
502 callback,
503 base::Owned(
504 new GetDocumentsParams(
505 params->start_changestamp,
506 params->root_feed_changestamp,
507 params->feed_list.release(),
508 params->should_fetch_multiple_feeds,
509 params->search_file_path,
510 params->search_query,
511 params->directory_resource_id,
512 params->callback,
513 params->ui_state.release())),
514 start_time));
515 return;
516 }
517
518 // Notify the observers that a document feed is fetched.
519 FOR_EACH_OBSERVER(Observer, observers_,
520 OnDocumentFeedFetched(num_accumulated_entries));
521
522 UMA_HISTOGRAM_TIMES("Gdata.EntireFeedLoadTime",
523 base::TimeTicks::Now() - start_time);
524
525 if (!callback.is_null())
526 callback.Run(params, error);
527 }
528
529 void GDataWapiFeedLoader::OnNotifyDocumentFeedFetched(
530 base::WeakPtr<GetDocumentsUiState> ui_state) {
531 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
532
533 if (!ui_state) {
534 // The ui state instance is already released, which means the fetching
535 // is done and we don't need to update any more.
536 return;
537 }
538
539 base::TimeDelta elapsed_time =
540 base::TimeTicks::Now() - ui_state->start_time;
541
542 if (ui_state->num_showing_documents + kFetchUiUpdateStep <=
543 ui_state->num_fetched_documents) {
544 ui_state->num_showing_documents += kFetchUiUpdateStep;
545 FOR_EACH_OBSERVER(Observer, observers_,
546 OnDocumentFeedFetched(ui_state->num_showing_documents));
547
548 int num_remaining_ui_updates =
549 (ui_state->num_fetched_documents - ui_state->num_showing_documents)
550 / kFetchUiUpdateStep;
551 if (num_remaining_ui_updates > 0) {
552 // Heuristically, we use fetched time duration to calculate the next
553 // UI update timing.
554 base::TimeDelta remaining_duration =
555 ui_state->feed_fetching_elapsed_time - elapsed_time;
556 MessageLoop::current()->PostDelayedTask(
557 FROM_HERE,
558 base::Bind(&GDataWapiFeedLoader::OnNotifyDocumentFeedFetched,
559 weak_ptr_factory_.GetWeakPtr(),
560 ui_state->weak_ptr_factory.GetWeakPtr()),
561 remaining_duration / num_remaining_ui_updates);
562 }
563 }
564 }
565
566 void GDataWapiFeedLoader::LoadFromCache(
567 bool should_load_from_server,
568 const FilePath& search_file_path,
569 const FindEntryCallback& callback) {
570 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
571
572 LoadRootFeedParams* params = new LoadRootFeedParams(search_file_path,
573 should_load_from_server,
574 callback);
575 FilePath path = cache_->GetCacheDirectoryPath(GDataCache::CACHE_TYPE_META);
576 if (UseLevelDB()) {
577 path = path.Append(kResourceMetadataDBFile);
578 directory_service_->InitFromDB(path, blocking_task_runner_,
579 base::Bind(
580 &GDataWapiFeedLoader::ContinueWithInitializedDirectoryService,
581 weak_ptr_factory_.GetWeakPtr(),
582 base::Owned(params)));
583 } else {
584 path = path.Append(kFilesystemProtoFile);
585 BrowserThread::GetBlockingPool()->PostTaskAndReply(FROM_HERE,
586 base::Bind(&LoadProtoOnBlockingPool, path, params),
587 base::Bind(&GDataWapiFeedLoader::OnProtoLoaded,
588 weak_ptr_factory_.GetWeakPtr(),
589 base::Owned(params)));
590 }
591 }
592
593 void GDataWapiFeedLoader::OnProtoLoaded(LoadRootFeedParams* params) {
594 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
595
596 // If we have already received updates from the server, bail out.
597 if (directory_service_->origin() == FROM_SERVER)
598 return;
599
600 // Update directory structure only if everything is OK and we haven't yet
601 // received the feed from the server yet.
602 if (params->load_error == GDATA_FILE_OK) {
603 DVLOG(1) << "ParseFromString";
604 if (directory_service_->ParseFromString(params->proto)) {
605 directory_service_->set_last_serialized(params->last_modified);
606 directory_service_->set_serialized_size(params->proto.size());
607 } else {
608 params->load_error = GDATA_FILE_ERROR_FAILED;
609 LOG(WARNING) << "Parse of cached proto file failed";
610 }
611 }
612
613 ContinueWithInitializedDirectoryService(params, params->load_error);
614 }
615
616 void GDataWapiFeedLoader::ContinueWithInitializedDirectoryService(
617 LoadRootFeedParams* params,
618 GDataFileError error) {
619 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
620
621 DVLOG(1) << "Time elapsed to load directory service from disk="
622 << (base::Time::Now() - params->load_start_time).InMilliseconds()
623 << " milliseconds";
624
625 FindEntryCallback callback = params->callback;
626 // If we got feed content from cache, try search over it.
627 if (error == GDATA_FILE_OK && !callback.is_null()) {
628 // Continue file content search operation if the delegate hasn't terminated
629 // this search branch already.
630 directory_service_->FindEntryByPathAndRunSync(params->search_file_path,
631 callback);
632 callback.Reset();
633 }
634
635 if (!params->should_load_from_server)
636 return;
637
638 // Decide the |initial_origin| to pass to ReloadFromServerIfNeeded().
639 // This is used to restore directory content origin to its initial value when
640 // we fail to retrieve the feed from server.
641 // By default, if directory content is not yet initialized, restore content
642 // origin to UNINITIALIZED in case of failure.
643 ContentOrigin initial_origin = UNINITIALIZED;
644 if (directory_service_->origin() != INITIALIZING) {
645 // If directory content is already initialized, restore content origin
646 // to FROM_CACHE in case of failure.
647 initial_origin = FROM_CACHE;
648 directory_service_->set_origin(REFRESHING);
649 }
650
651 // Kick of the retrieval of the feed from server. If we have previously
652 // |reported| to the original callback, then we just need to refresh the
653 // content without continuing search upon operation completion.
654 ReloadFromServerIfNeeded(initial_origin,
655 directory_service_->largest_changestamp(),
656 params->search_file_path,
657 callback);
658 }
659
660 void GDataWapiFeedLoader::SaveFileSystem() {
661 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
662
663 if (!ShouldSerializeFileSystemNow(directory_service_->serialized_size(),
664 directory_service_->last_serialized())) {
665 return;
666 }
667
668 if (UseLevelDB()) {
669 directory_service_->SaveToDB();
670 } else {
671 const FilePath path =
672 cache_->GetCacheDirectoryPath(GDataCache::CACHE_TYPE_META).Append(
673 kFilesystemProtoFile);
674 scoped_ptr<std::string> serialized_proto(new std::string());
675 directory_service_->SerializeToString(serialized_proto.get());
676 directory_service_->set_last_serialized(base::Time::Now());
677 directory_service_->set_serialized_size(serialized_proto->size());
678 util::PostBlockingPoolSequencedTask(
679 FROM_HERE,
680 blocking_task_runner_,
681 base::Bind(&SaveProtoOnBlockingPool, path,
682 base::Passed(serialized_proto.Pass())));
683 }
684 }
685
686 GDataFileError GDataWapiFeedLoader::UpdateFromFeed(
687 const std::vector<DocumentFeed*>& feed_list,
688 int start_changestamp,
689 int root_feed_changestamp) {
690 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
691 DVLOG(1) << "Updating directory with a feed";
692
693 std::set<FilePath> changed_dirs;
694
695 GDataWapiFeedProcessor feed_processor(directory_service_);
696 const GDataFileError error = feed_processor.ApplyFeeds(
697 feed_list,
698 start_changestamp,
699 root_feed_changestamp,
700 &changed_dirs);
701
702 // Don't send directory content change notification while performing
703 // the initial content retrieval.
704 const bool should_notify_directory_changed = (start_changestamp != 0);
705 if (should_notify_directory_changed) {
706 for (std::set<FilePath>::iterator dir_iter = changed_dirs.begin();
707 dir_iter != changed_dirs.end(); ++dir_iter) {
708 FOR_EACH_OBSERVER(Observer, observers_,
709 OnDirectoryChanged(*dir_iter));
710 }
711 }
712
713 return error;
714 }
715
716 } // namespace gdata
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698