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

Side by Side Diff: storage/browser/fileapi/recursive_operation_delegate.cc

Issue 1619733004: Run recursive file operations sequentially. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 11 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
« no previous file with comments | « storage/browser/fileapi/recursive_operation_delegate.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "storage/browser/fileapi/recursive_operation_delegate.h" 5 #include "storage/browser/fileapi/recursive_operation_delegate.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/single_thread_task_runner.h" 10 #include "base/single_thread_task_runner.h"
11 #include "base/thread_task_runner_handle.h" 11 #include "base/thread_task_runner_handle.h"
12 #include "storage/browser/fileapi/file_system_context.h" 12 #include "storage/browser/fileapi/file_system_context.h"
13 #include "storage/browser/fileapi/file_system_operation_runner.h" 13 #include "storage/browser/fileapi/file_system_operation_runner.h"
14 14
15 namespace storage { 15 namespace storage {
16 16
17 namespace {
18 // Don't start too many inflight operations.
19 const int kMaxInflightOperations = 5;
20 }
21
22 RecursiveOperationDelegate::RecursiveOperationDelegate( 17 RecursiveOperationDelegate::RecursiveOperationDelegate(
23 FileSystemContext* file_system_context) 18 FileSystemContext* file_system_context)
24 : file_system_context_(file_system_context), 19 : file_system_context_(file_system_context),
25 inflight_operations_(0),
26 canceled_(false), 20 canceled_(false),
27 error_behavior_(FileSystemOperation::ERROR_BEHAVIOR_ABORT), 21 error_behavior_(FileSystemOperation::ERROR_BEHAVIOR_ABORT),
28 failed_some_operations_(false) { 22 failed_some_operations_(false) {
29 } 23 }
30 24
31 RecursiveOperationDelegate::~RecursiveOperationDelegate() { 25 RecursiveOperationDelegate::~RecursiveOperationDelegate() {
32 } 26 }
33 27
34 void RecursiveOperationDelegate::Cancel() { 28 void RecursiveOperationDelegate::Cancel() {
35 canceled_ = true; 29 canceled_ = true;
36 OnCancel(); 30 OnCancel();
37 } 31 }
38 32
39 void RecursiveOperationDelegate::StartRecursiveOperation( 33 void RecursiveOperationDelegate::StartRecursiveOperation(
40 const FileSystemURL& root, 34 const FileSystemURL& root,
41 ErrorBehavior error_behavior, 35 ErrorBehavior error_behavior,
42 const StatusCallback& callback) { 36 const StatusCallback& callback) {
43 DCHECK(pending_directory_stack_.empty()); 37 DCHECK(pending_directory_stack_.empty());
44 DCHECK(pending_files_.empty()); 38 DCHECK(pending_files_.empty());
45 DCHECK_EQ(0, inflight_operations_);
46 39
47 error_behavior_ = error_behavior; 40 error_behavior_ = error_behavior;
48 callback_ = callback; 41 callback_ = callback;
49 42
50 TryProcessFile(root); 43 TryProcessFile(root);
51 } 44 }
52 45
53 void RecursiveOperationDelegate::TryProcessFile(const FileSystemURL& root) { 46 void RecursiveOperationDelegate::TryProcessFile(const FileSystemURL& root) {
54 ++inflight_operations_;
55 ProcessFile(root, base::Bind(&RecursiveOperationDelegate::DidTryProcessFile, 47 ProcessFile(root, base::Bind(&RecursiveOperationDelegate::DidTryProcessFile,
56 AsWeakPtr(), root)); 48 AsWeakPtr(), root));
57 } 49 }
58 50
59 FileSystemOperationRunner* RecursiveOperationDelegate::operation_runner() { 51 FileSystemOperationRunner* RecursiveOperationDelegate::operation_runner() {
60 return file_system_context_->operation_runner(); 52 return file_system_context_->operation_runner();
61 } 53 }
62 54
63 void RecursiveOperationDelegate::OnCancel() { 55 void RecursiveOperationDelegate::OnCancel() {
64 } 56 }
65 57
66 void RecursiveOperationDelegate::DidTryProcessFile( 58 void RecursiveOperationDelegate::DidTryProcessFile(
67 const FileSystemURL& root, 59 const FileSystemURL& root,
68 base::File::Error error) { 60 base::File::Error error) {
69 DCHECK(pending_directory_stack_.empty()); 61 DCHECK(pending_directory_stack_.empty());
70 DCHECK(pending_files_.empty()); 62 DCHECK(pending_files_.empty());
71 DCHECK_EQ(1, inflight_operations_);
72 63
73 --inflight_operations_;
74 if (canceled_ || error != base::File::FILE_ERROR_NOT_A_FILE) { 64 if (canceled_ || error != base::File::FILE_ERROR_NOT_A_FILE) {
75 Done(error); 65 Done(error);
76 return; 66 return;
77 } 67 }
78 68
79 pending_directory_stack_.push(std::queue<FileSystemURL>()); 69 pending_directory_stack_.push(std::queue<FileSystemURL>());
80 pending_directory_stack_.top().push(root); 70 pending_directory_stack_.top().push(root);
81 ProcessNextDirectory(); 71 ProcessNextDirectory();
82 } 72 }
83 73
84 void RecursiveOperationDelegate::ProcessNextDirectory() { 74 void RecursiveOperationDelegate::ProcessNextDirectory() {
85 DCHECK(pending_files_.empty()); 75 DCHECK(pending_files_.empty());
86 DCHECK(!pending_directory_stack_.empty()); 76 DCHECK(!pending_directory_stack_.empty());
87 DCHECK(!pending_directory_stack_.top().empty()); 77 DCHECK(!pending_directory_stack_.top().empty());
88 DCHECK_EQ(0, inflight_operations_);
89 78
90 const FileSystemURL& url = pending_directory_stack_.top().front(); 79 const FileSystemURL& url = pending_directory_stack_.top().front();
91 80
92 ++inflight_operations_;
93 ProcessDirectory( 81 ProcessDirectory(
94 url, 82 url,
95 base::Bind( 83 base::Bind(
96 &RecursiveOperationDelegate::DidProcessDirectory, AsWeakPtr())); 84 &RecursiveOperationDelegate::DidProcessDirectory, AsWeakPtr()));
97 } 85 }
98 86
99 void RecursiveOperationDelegate::DidProcessDirectory( 87 void RecursiveOperationDelegate::DidProcessDirectory(
100 base::File::Error error) { 88 base::File::Error error) {
101 DCHECK(pending_files_.empty()); 89 DCHECK(pending_files_.empty());
102 DCHECK(!pending_directory_stack_.empty()); 90 DCHECK(!pending_directory_stack_.empty());
103 DCHECK(!pending_directory_stack_.top().empty()); 91 DCHECK(!pending_directory_stack_.top().empty());
104 DCHECK_EQ(1, inflight_operations_);
105 92
106 --inflight_operations_;
107 if (canceled_ || error != base::File::FILE_OK) { 93 if (canceled_ || error != base::File::FILE_OK) {
108 Done(error); 94 Done(error);
109 return; 95 return;
110 } 96 }
111 97
112 const FileSystemURL& parent = pending_directory_stack_.top().front(); 98 const FileSystemURL& parent = pending_directory_stack_.top().front();
113 pending_directory_stack_.push(std::queue<FileSystemURL>()); 99 pending_directory_stack_.push(std::queue<FileSystemURL>());
114 operation_runner()->ReadDirectory( 100 operation_runner()->ReadDirectory(
115 parent, 101 parent,
116 base::Bind(&RecursiveOperationDelegate::DidReadDirectory, 102 base::Bind(&RecursiveOperationDelegate::DidReadDirectory,
117 AsWeakPtr(), parent)); 103 AsWeakPtr(), parent));
118 } 104 }
119 105
120 void RecursiveOperationDelegate::DidReadDirectory( 106 void RecursiveOperationDelegate::DidReadDirectory(
121 const FileSystemURL& parent, 107 const FileSystemURL& parent,
122 base::File::Error error, 108 base::File::Error error,
123 const FileEntryList& entries, 109 const FileEntryList& entries,
124 bool has_more) { 110 bool has_more) {
125 DCHECK(!pending_directory_stack_.empty()); 111 DCHECK(!pending_directory_stack_.empty());
126 DCHECK_EQ(0, inflight_operations_);
127 112
128 if (canceled_ || error != base::File::FILE_OK) { 113 if (canceled_ || error != base::File::FILE_OK) {
129 Done(error); 114 Done(error);
130 return; 115 return;
131 } 116 }
132 117
133 for (size_t i = 0; i < entries.size(); i++) { 118 for (size_t i = 0; i < entries.size(); i++) {
134 FileSystemURL url = file_system_context_->CreateCrackedFileSystemURL( 119 FileSystemURL url = file_system_context_->CreateCrackedFileSystemURL(
135 parent.origin(), 120 parent.origin(),
136 parent.mount_type(), 121 parent.mount_type(),
137 parent.virtual_path().Append(entries[i].name)); 122 parent.virtual_path().Append(entries[i].name));
138 if (entries[i].is_directory) 123 if (entries[i].is_directory)
139 pending_directory_stack_.top().push(url); 124 pending_directory_stack_.top().push(url);
140 else 125 else
141 pending_files_.push(url); 126 pending_files_.push(url);
142 } 127 }
143 128
144 // Wait for next entries. 129 // Wait for next entries.
145 if (has_more) 130 if (has_more)
146 return; 131 return;
147 132
148 ProcessPendingFiles(); 133 ProcessPendingFiles();
149 } 134 }
150 135
151 void RecursiveOperationDelegate::ProcessPendingFiles() { 136 void RecursiveOperationDelegate::ProcessPendingFiles() {
152 DCHECK(!pending_directory_stack_.empty()); 137 DCHECK(!pending_directory_stack_.empty());
153 138
154 if ((pending_files_.empty() || canceled_) && inflight_operations_ == 0) { 139 if (pending_files_.empty() || canceled_) {
fukino 2016/01/22 06:43:29 I think this check for inflight_operations_ can si
155 ProcessSubDirectory(); 140 ProcessSubDirectory();
156 return; 141 return;
157 } 142 }
158 143
159 // Do not post any new tasks. 144 // Do not post any new tasks.
160 if (canceled_) 145 if (canceled_)
161 return; 146 return;
162 147
163 // Run ProcessFile in parallel (upto kMaxInflightOperations). 148 // Run ProcessFile.
164 scoped_refptr<base::SingleThreadTaskRunner> current_task_runner = 149 scoped_refptr<base::SingleThreadTaskRunner> current_task_runner =
165 base::ThreadTaskRunnerHandle::Get(); 150 base::ThreadTaskRunnerHandle::Get();
166 while (!pending_files_.empty() && 151 if (!pending_files_.empty()) {
167 inflight_operations_ < kMaxInflightOperations) {
168 ++inflight_operations_;
169 current_task_runner->PostTask( 152 current_task_runner->PostTask(
170 FROM_HERE, 153 FROM_HERE,
171 base::Bind(&RecursiveOperationDelegate::ProcessFile, AsWeakPtr(), 154 base::Bind(&RecursiveOperationDelegate::ProcessFile, AsWeakPtr(),
172 pending_files_.front(), 155 pending_files_.front(),
173 base::Bind(&RecursiveOperationDelegate::DidProcessFile, 156 base::Bind(&RecursiveOperationDelegate::DidProcessFile,
174 AsWeakPtr(), pending_files_.front()))); 157 AsWeakPtr(), pending_files_.front())));
175 pending_files_.pop(); 158 pending_files_.pop();
176 } 159 }
177 } 160 }
178 161
179 void RecursiveOperationDelegate::DidProcessFile(const FileSystemURL& url, 162 void RecursiveOperationDelegate::DidProcessFile(const FileSystemURL& url,
180 base::File::Error error) { 163 base::File::Error error) {
181 --inflight_operations_;
182
183 if (error != base::File::FILE_OK) { 164 if (error != base::File::FILE_OK) {
184 if (error_behavior_ == FileSystemOperation::ERROR_BEHAVIOR_ABORT) { 165 if (error_behavior_ == FileSystemOperation::ERROR_BEHAVIOR_ABORT) {
185 // If an error occurs, invoke Done immediately (even if there remain 166 // If an error occurs, invoke Done immediately (even if there remain
186 // running operations). It is because in the callback, this instance is 167 // running operations). It is because in the callback, this instance is
187 // deleted. 168 // deleted.
188 Done(error); 169 Done(error);
189 return; 170 return;
190 } 171 }
191 172
192 failed_some_operations_ = true; 173 failed_some_operations_ = true;
193 } 174 }
194 175
195 ProcessPendingFiles(); 176 ProcessPendingFiles();
196 } 177 }
197 178
198 void RecursiveOperationDelegate::ProcessSubDirectory() { 179 void RecursiveOperationDelegate::ProcessSubDirectory() {
199 DCHECK(pending_files_.empty()); 180 DCHECK(pending_files_.empty());
200 DCHECK(!pending_directory_stack_.empty()); 181 DCHECK(!pending_directory_stack_.empty());
201 DCHECK_EQ(0, inflight_operations_);
202 182
203 if (canceled_) { 183 if (canceled_) {
204 Done(base::File::FILE_ERROR_ABORT); 184 Done(base::File::FILE_ERROR_ABORT);
205 return; 185 return;
206 } 186 }
207 187
208 if (!pending_directory_stack_.top().empty()) { 188 if (!pending_directory_stack_.top().empty()) {
209 // There remain some sub directories. Process them first. 189 // There remain some sub directories. Process them first.
210 ProcessNextDirectory(); 190 ProcessNextDirectory();
211 return; 191 return;
212 } 192 }
213 193
214 // All subdirectories are processed. 194 // All subdirectories are processed.
215 pending_directory_stack_.pop(); 195 pending_directory_stack_.pop();
216 if (pending_directory_stack_.empty()) { 196 if (pending_directory_stack_.empty()) {
217 // All files/directories are processed. 197 // All files/directories are processed.
218 Done(base::File::FILE_OK); 198 Done(base::File::FILE_OK);
219 return; 199 return;
220 } 200 }
221 201
222 DCHECK(!pending_directory_stack_.top().empty()); 202 DCHECK(!pending_directory_stack_.top().empty());
223 ++inflight_operations_;
224 PostProcessDirectory( 203 PostProcessDirectory(
225 pending_directory_stack_.top().front(), 204 pending_directory_stack_.top().front(),
226 base::Bind(&RecursiveOperationDelegate::DidPostProcessDirectory, 205 base::Bind(&RecursiveOperationDelegate::DidPostProcessDirectory,
227 AsWeakPtr())); 206 AsWeakPtr()));
228 } 207 }
229 208
230 void RecursiveOperationDelegate::DidPostProcessDirectory( 209 void RecursiveOperationDelegate::DidPostProcessDirectory(
231 base::File::Error error) { 210 base::File::Error error) {
232 DCHECK(pending_files_.empty()); 211 DCHECK(pending_files_.empty());
233 DCHECK(!pending_directory_stack_.empty()); 212 DCHECK(!pending_directory_stack_.empty());
234 DCHECK(!pending_directory_stack_.top().empty()); 213 DCHECK(!pending_directory_stack_.top().empty());
235 DCHECK_EQ(1, inflight_operations_);
236 214
237 --inflight_operations_;
238 pending_directory_stack_.top().pop(); 215 pending_directory_stack_.top().pop();
239 if (canceled_ || error != base::File::FILE_OK) { 216 if (canceled_ || error != base::File::FILE_OK) {
240 Done(error); 217 Done(error);
241 return; 218 return;
242 } 219 }
243 220
244 ProcessSubDirectory(); 221 ProcessSubDirectory();
245 } 222 }
246 223
247 void RecursiveOperationDelegate::Done(base::File::Error error) { 224 void RecursiveOperationDelegate::Done(base::File::Error error) {
248 if (canceled_ && error == base::File::FILE_OK) { 225 if (canceled_ && error == base::File::FILE_OK) {
249 callback_.Run(base::File::FILE_ERROR_ABORT); 226 callback_.Run(base::File::FILE_ERROR_ABORT);
250 } else { 227 } else {
251 if (error_behavior_ == FileSystemOperation::ERROR_BEHAVIOR_SKIP && 228 if (error_behavior_ == FileSystemOperation::ERROR_BEHAVIOR_SKIP &&
252 failed_some_operations_) 229 failed_some_operations_)
253 callback_.Run(base::File::FILE_ERROR_FAILED); 230 callback_.Run(base::File::FILE_ERROR_FAILED);
254 else 231 else
255 callback_.Run(error); 232 callback_.Run(error);
256 } 233 }
257 } 234 }
258 235
259 } // namespace storage 236 } // namespace storage
OLDNEW
« no previous file with comments | « storage/browser/fileapi/recursive_operation_delegate.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698