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

Side by Side Diff: webkit/plugins/ppapi/quota_file_io.cc

Issue 7433006: Pepper quota support (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: '' Created 9 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) 2011 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 "webkit/plugins/ppapi/quota_file_io.h"
6
7 #include "base/stl_util.h"
8 #include "webkit/plugins/ppapi/ppapi_plugin_instance.h"
9
10 using base::PlatformFile;
11 using base::PlatformFileError;
12 using quota::StorageType;
13
14 namespace webkit {
15 namespace ppapi {
16
17 namespace {
18 StorageType PPFileSystemTypeToQuotaStorageType(PP_FileSystemType type) {
19 switch (type) {
20 case PP_FILESYSTEMTYPE_LOCALPERSISTENT:
21 return quota::kStorageTypePersistent;
22 case PP_FILESYSTEMTYPE_LOCALTEMPORARY:
23 return quota::kStorageTypeTemporary;
24 default:
25 return quota::kStorageTypeUnknown;
26 }
27 NOTREACHED();
28 }
29 } // namespace
30
31 class QuotaFileIO::PendingOperationBase {
32 public:
33 virtual ~PendingOperationBase() {}
34
35 // Either one of Run() or DidFail() is called (the latter is called when
36 // there was more than one error during quota queries).
37 virtual void Run() = 0;
38 virtual void DidFail(PlatformFileError error) = 0;
39
40 protected:
41 PendingOperationBase(QuotaFileIO* quota_io, bool is_will_operation)
42 : quota_io_(quota_io), is_will_operation_(is_will_operation) {
43 DCHECK(quota_io_);
44 quota_io_->WillUpdate();
45 }
46
47 QuotaFileIO* quota_io_;
48 const bool is_will_operation_;
49 };
50
51 class QuotaFileIO::WriteOperation : public PendingOperationBase {
52 public:
53 WriteOperation(QuotaFileIO* quota_io,
54 bool is_will_operation,
55 int64_t offset,
56 const char* buffer,
57 int32_t bytes_to_write,
58 WriteCallback* callback)
59 : PendingOperationBase(quota_io, is_will_operation),
60 offset_(offset),
61 bytes_to_write_(bytes_to_write),
62 callback_(callback),
63 finished_(false),
64 status_(base::PLATFORM_FILE_OK),
65 bytes_written_(0),
66 callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
67 if (!is_will_operation) {
68 // TODO(kinuko): check the API convention if we really need to keep a
69 // copy of the buffer during the async write operations.
70 buffer_.reset(new char[bytes_to_write]);
71 memcpy(buffer_.get(), buffer, bytes_to_write);
72 }
73 }
74 virtual ~WriteOperation() {}
75 virtual void Run() OVERRIDE {
76 DCHECK(quota_io_);
77 if (quota_io_->CheckIfExceedsQuota(offset_ + bytes_to_write_)) {
78 DidFail(base::PLATFORM_FILE_ERROR_NO_SPACE);
79 return;
80 }
81 if (is_will_operation_) {
82 // Assuming the write will succeed.
83 DidFinish(base::PLATFORM_FILE_OK, bytes_to_write_);
84 return;
85 }
86 DCHECK(buffer_.get());
87 if (!base::FileUtilProxy::Write(
88 quota_io_->instance_->delegate()->GetFileThreadMessageLoopProxy(),
89 quota_io_->file_, offset_, buffer_.get(), bytes_to_write_,
90 callback_factory_.NewCallback(&WriteOperation::DidFinish))) {
91 DidFail(base::PLATFORM_FILE_ERROR_FAILED);
92 return;
93 }
94 }
95
96 virtual void DidFail(PlatformFileError error) OVERRIDE {
97 DidFinish(error, 0);
98 }
99
100 bool finished() const { return finished_; }
101
102 void RunCallback() {
103 DCHECK(callback_.get());
104 callback_->Run(status_, bytes_written_);
105 callback_.reset();
106 delete this;
107 }
108
109 private:
110 void DidFinish(PlatformFileError status, int bytes_written) {
111 finished_ = true;
112 status_ = status;
113 bytes_written_ = bytes_written;
114 int64_t max_offset =
115 (status != base::PLATFORM_FILE_OK) ? 0 : offset_ + bytes_written;
116 // This may delete itself by calling RunCallback.
117 quota_io_->DidWrite(this, max_offset);
118 }
119
120 const int64_t offset_;
121 scoped_array<char> buffer_;
122 const int32_t bytes_to_write_;
123 scoped_ptr<WriteCallback> callback_;
124 bool finished_;
125 PlatformFileError status_;
126 int64_t bytes_written_;
127 base::ScopedCallbackFactory<QuotaFileIO::WriteOperation> callback_factory_;
128 };
129
130 class QuotaFileIO::SetLengthOperation : public PendingOperationBase {
131 public:
132 SetLengthOperation(QuotaFileIO* quota_io,
133 bool is_will_operation,
134 int64_t length,
135 StatusCallback* callback)
136 : PendingOperationBase(quota_io, is_will_operation),
137 length_(length),
138 callback_(callback),
139 callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {}
140 virtual ~SetLengthOperation() {}
141
142 virtual void Run() OVERRIDE {
143 DCHECK(quota_io_);
144 if (quota_io_->CheckIfExceedsQuota(length_)) {
145 DidFail(base::PLATFORM_FILE_ERROR_NO_SPACE);
146 return;
147 }
148 if (is_will_operation_) {
149 DidFinish(base::PLATFORM_FILE_OK);
150 return;
151 }
152 if (!base::FileUtilProxy::Truncate(
153 quota_io_->instance_->delegate()->GetFileThreadMessageLoopProxy(),
154 quota_io_->file_, length_,
155 callback_factory_.NewCallback(&SetLengthOperation::DidFinish))) {
156 DidFail(base::PLATFORM_FILE_ERROR_FAILED);
157 return;
158 }
159 }
160
161 virtual void DidFail(PlatformFileError error) OVERRIDE {
162 DidFinish(error);
163 }
164
165 private:
166 void DidFinish(PlatformFileError status) {
167 quota_io_->DidSetLength(status, length_);
168 DCHECK(callback_.get());
169 callback_->Run(status);
170 callback_.reset();
171 delete this;
172 }
173
174 int64_t length_;
175 scoped_ptr<StatusCallback> callback_;
176 base::ScopedCallbackFactory<QuotaFileIO::SetLengthOperation>
177 callback_factory_;
178 };
179
180 // QuotaFileIO --------------------------------------------------------------
181
182 QuotaFileIO::QuotaFileIO(
183 PluginInstance* instance,
184 PlatformFile file,
185 const GURL& file_url,
186 PP_FileSystemType type)
187 : instance_(instance),
188 file_(file),
189 file_url_(file_url),
190 storage_type_(PPFileSystemTypeToQuotaStorageType(type)),
191 cached_file_size_(0),
192 cached_available_space_(0),
193 outstanding_quota_queries_(0),
194 outstanding_errors_(0),
195 max_written_offset_(0),
196 inflight_operations_(0),
197 callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
198 DCHECK(instance_);
199 DCHECK_NE(base::kInvalidPlatformFileValue, file_);
200 DCHECK_NE(quota::kStorageTypeUnknown, storage_type_);
201 }
202
203 QuotaFileIO::~QuotaFileIO() {
204 // Note that this doesn't dispatch pending callbacks.
205 STLDeleteContainerPointers(pending_operations_.begin(),
206 pending_operations_.end());
207 }
208
209 bool QuotaFileIO::Write(
210 int64_t offset, const char* buffer, int32_t bytes_to_write,
211 WriteCallback* callback) {
212 WriteOperation* op = new WriteOperation(
213 this, false, offset, buffer, bytes_to_write, callback);
214 return RegisterOperationForQuotaChecks(op);
215 }
216
217 bool QuotaFileIO::SetLength(int64_t length, StatusCallback* callback) {
218 DCHECK(pending_operations_.empty());
219 SetLengthOperation* op = new SetLengthOperation(
220 this, false, length, callback);
221 return RegisterOperationForQuotaChecks(op);
222 }
223
224 bool QuotaFileIO::WillWrite(
225 int64_t offset, int32_t bytes_to_write, WriteCallback* callback) {
226 WriteOperation* op = new WriteOperation(
227 this, true, offset, NULL, bytes_to_write, callback);
228 return RegisterOperationForQuotaChecks(op);
229 }
230
231 bool QuotaFileIO::WillSetLength(int64_t length, StatusCallback* callback) {
232 DCHECK(pending_operations_.empty());
233 SetLengthOperation* op = new SetLengthOperation(this, true, length, callback);
234 return RegisterOperationForQuotaChecks(op);
235 }
236
237 bool QuotaFileIO::RegisterOperationForQuotaChecks(
238 PendingOperationBase* op_ptr) {
239 scoped_ptr<PendingOperationBase> op(op_ptr);
240 if (pending_operations_.empty()) {
241 // This is the first pending quota check. Run querying the file size
242 // and available space.
243 outstanding_quota_queries_ = 0;
244 outstanding_errors_ = 0;
245
246 // Query the file size.
247 ++outstanding_quota_queries_;
248 if (!base::FileUtilProxy::GetFileInfoFromPlatformFile(
249 instance_->delegate()->GetFileThreadMessageLoopProxy(), file_,
250 callback_factory_.NewCallback(
251 &QuotaFileIO::DidQueryInfoForQuota))) {
252 // This makes the call fail synchronously; we do not fire the callback
253 // here but just delete the operation and return false.
254 return false;
255 }
256
257 // Query the current available space.
258 ++outstanding_quota_queries_;
259 instance_->delegate()->QueryAvailableSpace(
260 GURL(file_url_.path()).GetOrigin(), storage_type_,
261 callback_factory_.NewCallback(&QuotaFileIO::DidQueryAvailableSpace));
262 }
263 pending_operations_.push_back(op.release());
264 return true;
265 }
266
267 void QuotaFileIO::DidQueryInfoForQuota(
268 base::PlatformFileError error_code,
269 const base::PlatformFileInfo& file_info) {
270 if (error_code != base::PLATFORM_FILE_OK)
271 ++outstanding_errors_;
272 cached_file_size_ = file_info.size;
273 DCHECK_GT(outstanding_quota_queries_, 0);
274 if (--outstanding_quota_queries_ == 0)
275 DidQueryForQuotaCheck();
276 }
277
278 void QuotaFileIO::DidQueryAvailableSpace(int64_t avail_space) {
279 cached_available_space_ = avail_space;
280 DCHECK_GT(outstanding_quota_queries_, 0);
281 if (--outstanding_quota_queries_ == 0)
282 DidQueryForQuotaCheck();
283 }
284
285 void QuotaFileIO::DidQueryForQuotaCheck() {
286 DCHECK(!pending_operations_.empty());
287 DCHECK_GT(inflight_operations_, 0);
288 for (std::deque<PendingOperationBase*>::iterator iter =
289 pending_operations_.begin();
290 iter != pending_operations_.end();
291 ++iter) {
292 PendingOperationBase* op = *iter;
293 if (outstanding_errors_ > 0) {
294 op->DidFail(base::PLATFORM_FILE_ERROR_FAILED);
295 continue;
296 }
297 op->Run();
298 }
299 }
300
301 bool QuotaFileIO::CheckIfExceedsQuota(int64_t new_file_size) const {
302 DCHECK_GE(cached_file_size_, 0);
303 DCHECK_GE(cached_available_space_, 0);
304 return new_file_size - cached_file_size_ > cached_available_space_;
305 }
306
307 void QuotaFileIO::WillUpdate() {
308 if (inflight_operations_++ == 0) {
309 instance_->delegate()->WillUpdateFile(file_url_);
310 DCHECK_EQ(0, max_written_offset_);
311 }
312 }
313
314 void QuotaFileIO::DidWrite(WriteOperation* op,
315 int64_t written_offset_end) {
316 max_written_offset_ = std::max(max_written_offset_, written_offset_end);
317 DCHECK_GT(inflight_operations_, 0);
318 DCHECK(!pending_operations_.empty());
319 // Fire callbacks for finished operations.
320 while (!pending_operations_.empty()) {
321 WriteOperation* op = static_cast<WriteOperation*>(
322 pending_operations_.front());
323 if (!op->finished())
324 break;
325 op->RunCallback();
326 pending_operations_.pop_front();
327 }
328 // If we have no more pending writes, notify the browser that we did
329 // update the file.
330 if (--inflight_operations_ == 0) {
331 DCHECK(pending_operations_.empty());
332 int64_t growth = max_written_offset_ - cached_file_size_;
333 growth = growth < 0 ? 0 : growth;
334 instance_->delegate()->DidUpdateFile(file_url_, growth);
335 max_written_offset_ = 0;
336 }
337 }
338
339 void QuotaFileIO::DidSetLength(PlatformFileError error, int64_t new_file_size) {
340 DCHECK_EQ(1, inflight_operations_);
341 pending_operations_.pop_front();
342 DCHECK(pending_operations_.empty());
343 int64_t delta = (error != base::PLATFORM_FILE_OK) ? 0 :
344 new_file_size - cached_file_size_;
345 instance_->delegate()->DidUpdateFile(file_url_, delta);
346 inflight_operations_ = 0;
347 }
348
349 } // namespace ppapi
350 } // namespace webkit
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698