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

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

Powered by Google App Engine
This is Rietveld 408576698