Ensure low-memory renderers retry failed loads correctly.
[chromium-blink-merge.git] / components / drive / file_system / open_file_operation.cc
blob54da778b36ac1a8e2006827bce13822139cfbeb7
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
3 // found in the LICENSE file.
5 #include "components/drive/file_system/open_file_operation.h"
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/callback_helpers.h"
10 #include "base/files/file_path.h"
11 #include "base/logging.h"
12 #include "base/task_runner_util.h"
13 #include "base/thread_task_runner_handle.h"
14 #include "components/drive/drive.pb.h"
15 #include "components/drive/file_cache.h"
16 #include "components/drive/file_errors.h"
17 #include "components/drive/file_system/create_file_operation.h"
18 #include "components/drive/file_system/download_operation.h"
19 #include "components/drive/file_system/operation_delegate.h"
20 #include "components/drive/job_scheduler.h"
22 namespace drive {
23 namespace file_system {
25 OpenFileOperation::OpenFileOperation(
26 base::SequencedTaskRunner* blocking_task_runner,
27 OperationDelegate* delegate,
28 JobScheduler* scheduler,
29 internal::ResourceMetadata* metadata,
30 internal::FileCache* cache,
31 const base::FilePath& temporary_file_directory)
32 : blocking_task_runner_(blocking_task_runner),
33 delegate_(delegate),
34 cache_(cache),
35 create_file_operation_(new CreateFileOperation(
36 blocking_task_runner, delegate, metadata)),
37 download_operation_(new DownloadOperation(
38 blocking_task_runner, delegate, scheduler,
39 metadata, cache, temporary_file_directory)),
40 weak_ptr_factory_(this) {
43 OpenFileOperation::~OpenFileOperation() {
46 void OpenFileOperation::OpenFile(const base::FilePath& file_path,
47 OpenMode open_mode,
48 const std::string& mime_type,
49 const OpenFileCallback& callback) {
50 DCHECK(thread_checker_.CalledOnValidThread());
51 DCHECK(!callback.is_null());
53 switch (open_mode) {
54 case OPEN_FILE:
55 // It is not necessary to create a new file even if not exists.
56 // So call OpenFileAfterCreateFile directly with FILE_ERROR_OK
57 // to skip file creation.
58 OpenFileAfterCreateFile(file_path, callback, FILE_ERROR_OK);
59 break;
60 case CREATE_FILE:
61 create_file_operation_->CreateFile(
62 file_path,
63 true, // exclusive: fail if already exists
64 mime_type,
65 base::Bind(&OpenFileOperation::OpenFileAfterCreateFile,
66 weak_ptr_factory_.GetWeakPtr(), file_path, callback));
67 break;
68 case OPEN_OR_CREATE_FILE:
69 create_file_operation_->CreateFile(
70 file_path,
71 false, // not-exclusive
72 mime_type,
73 base::Bind(&OpenFileOperation::OpenFileAfterCreateFile,
74 weak_ptr_factory_.GetWeakPtr(), file_path, callback));
75 break;
79 void OpenFileOperation::OpenFileAfterCreateFile(
80 const base::FilePath& file_path,
81 const OpenFileCallback& callback,
82 FileError error) {
83 DCHECK(thread_checker_.CalledOnValidThread());
84 DCHECK(!callback.is_null());
86 if (error != FILE_ERROR_OK) {
87 callback.Run(error, base::FilePath(), base::Closure());
88 return;
91 download_operation_->EnsureFileDownloadedByPath(
92 file_path,
93 ClientContext(USER_INITIATED),
94 GetFileContentInitializedCallback(),
95 google_apis::GetContentCallback(),
96 base::Bind(
97 &OpenFileOperation::OpenFileAfterFileDownloaded,
98 weak_ptr_factory_.GetWeakPtr(), callback));
101 void OpenFileOperation::OpenFileAfterFileDownloaded(
102 const OpenFileCallback& callback,
103 FileError error,
104 const base::FilePath& local_file_path,
105 scoped_ptr<ResourceEntry> entry) {
106 DCHECK(thread_checker_.CalledOnValidThread());
107 DCHECK(!callback.is_null());
109 if (error == FILE_ERROR_OK) {
110 DCHECK(entry);
111 DCHECK(entry->has_file_specific_info());
112 if (entry->file_specific_info().is_hosted_document())
113 // No support for opening a hosted document.
114 error = FILE_ERROR_INVALID_OPERATION;
117 if (error != FILE_ERROR_OK) {
118 callback.Run(error, base::FilePath(), base::Closure());
119 return;
122 scoped_ptr<base::ScopedClosureRunner>* file_closer =
123 new scoped_ptr<base::ScopedClosureRunner>;
124 base::PostTaskAndReplyWithResult(
125 blocking_task_runner_.get(),
126 FROM_HERE,
127 base::Bind(&internal::FileCache::OpenForWrite,
128 base::Unretained(cache_),
129 entry->local_id(),
130 file_closer),
131 base::Bind(&OpenFileOperation::OpenFileAfterOpenForWrite,
132 weak_ptr_factory_.GetWeakPtr(),
133 local_file_path,
134 entry->local_id(),
135 callback,
136 base::Owned(file_closer)));
139 void OpenFileOperation::OpenFileAfterOpenForWrite(
140 const base::FilePath& local_file_path,
141 const std::string& local_id,
142 const OpenFileCallback& callback,
143 scoped_ptr<base::ScopedClosureRunner>* file_closer,
144 FileError error) {
145 DCHECK(thread_checker_.CalledOnValidThread());
146 DCHECK(!callback.is_null());
148 if (error != FILE_ERROR_OK) {
149 callback.Run(error, base::FilePath(), base::Closure());
150 return;
153 ++open_files_[local_id];
154 callback.Run(error, local_file_path,
155 base::Bind(&OpenFileOperation::CloseFile,
156 weak_ptr_factory_.GetWeakPtr(),
157 local_id,
158 base::Passed(file_closer)));
161 void OpenFileOperation::CloseFile(
162 const std::string& local_id,
163 scoped_ptr<base::ScopedClosureRunner> file_closer) {
164 DCHECK(thread_checker_.CalledOnValidThread());
165 DCHECK_GT(open_files_[local_id], 0);
167 if (--open_files_[local_id] == 0) {
168 // All clients closes this file, so notify to upload the file.
169 open_files_.erase(local_id);
170 delegate_->OnEntryUpdatedByOperation(ClientContext(USER_INITIATED),
171 local_id);
173 // Clients may have enlarged the file. By FreeDiskpSpaceIfNeededFor(0),
174 // we try to ensure (0 + the-minimum-safe-margin = 512MB as of now) space.
175 blocking_task_runner_->PostTask(
176 FROM_HERE,
177 base::Bind(base::IgnoreResult(
178 base::Bind(&internal::FileCache::FreeDiskSpaceIfNeededFor,
179 base::Unretained(cache_),
180 0))));
184 } // namespace file_system
185 } // namespace drive