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

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: fixed tests Created 9 years, 5 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_->RegisterOperation(this);
45 quota_io_->WillUpdate();
46 }
47
48 QuotaFileIO* quota_io_;
49 const bool is_will_operation_;
50 };
51
52 class QuotaFileIO::WriteOperation : public PendingOperationBase {
53 public:
54 WriteOperation(QuotaFileIO* quota_io,
55 bool is_will_operation,
56 int64_t offset,
57 const char* buffer,
58 int32_t bytes_to_write,
59 WriteCallback* callback)
60 : PendingOperationBase(quota_io, is_will_operation),
61 offset_(offset),
62 bytes_to_write_(bytes_to_write),
63 callback_(callback),
64 callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
65 if (!is_will_operation) {
66 DCHECK(buffer);
67 buffer_.reset(new char[bytes_to_write]);
michaeln 2011/07/26 19:25:08 Do we need the copy the bytes? If the caller is re
kinuko 2011/07/27 09:33:14 Right. I wanted to keep the pointers to make my t
yzshen1 2011/07/27 18:26:07 The reason why PPB_FileIO_Impl doesn't need to mak
kinuko 2011/07/28 14:11:00 Ok, let me revert this change for now and keep a c
68 memcpy(buffer_.get(), buffer, bytes_to_write);
69 }
70 }
71
72 virtual ~WriteOperation() OVERRIDE {
yzshen1 2011/07/26 19:26:44 I think it is not OVERRIDE, is it?
kinuko 2011/07/27 09:33:14 Done.
73 if (callback_.get())
74 callback_->Run(base::PLATFORM_FILE_ERROR_ABORT, 0);
75 }
76 virtual void Run() OVERRIDE {
77 DCHECK(quota_io_);
78 if (quota_io_->CheckIfExceedsQuota(offset_ + bytes_to_write_)) {
yzshen1 2011/07/26 19:26:44 In addition to the problem that I mentioned in ano
michaeln 2011/07/26 19:58:07 Doh... right... my vote would be to make QuotaFile
kinuko 2011/07/27 09:33:14 Done. Thanks for your careful review. Changed the
79 DidFail(base::PLATFORM_FILE_ERROR_NO_SPACE);
80 return;
81 }
82 if (is_will_operation_) {
83 // Assuming the write will succeed.
84 DidFinish(base::PLATFORM_FILE_OK, bytes_to_write_);
85 return;
86 }
87 DCHECK(buffer_.get());
88 if (!base::FileUtilProxy::Write(
89 quota_io_->instance_->delegate()->GetFileThreadMessageLoopProxy(),
90 quota_io_->file_, offset_, buffer_.get(), bytes_to_write_,
91 callback_factory_.NewCallback(&WriteOperation::DidFinish))) {
92 DidFail(base::PLATFORM_FILE_ERROR_FAILED);
93 return;
94 }
95 }
96
97 virtual void DidFail(PlatformFileError error) OVERRIDE {
98 DidFinish(error, 0);
99 }
100
101 private:
102 void DidFinish(PlatformFileError status, int bytes_written) {
103 quota_io_->DidWrite(offset_ + bytes_written);
104 quota_io_->UnregisterOperation(this);
105 DCHECK(callback_.get());
106 callback_->Run(status, bytes_written);
107 callback_.reset();
108 delete this;
109 }
110
111 const int64_t offset_;
112 scoped_array<char> buffer_;
113 const int32_t bytes_to_write_;
114 scoped_ptr<WriteCallback> callback_;
115 base::ScopedCallbackFactory<QuotaFileIO::WriteOperation> callback_factory_;
116 };
117
118 class QuotaFileIO::SetLengthOperation : public PendingOperationBase {
119 public:
120 SetLengthOperation(QuotaFileIO* quota_io,
121 bool is_will_operation,
122 int64_t length,
123 StatusCallback* callback)
124 : PendingOperationBase(quota_io, is_will_operation),
125 length_(length),
126 callback_(callback),
127 callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {}
128
129 virtual ~SetLengthOperation() OVERRIDE {
yzshen1 2011/07/26 19:26:44 I think it is not OVERRIDE, is it?
kinuko 2011/07/27 09:33:14 Done.
130 if (callback_.get())
131 callback_->Run(base::PLATFORM_FILE_ERROR_ABORT);
132 }
133
134 virtual void Run() OVERRIDE {
135 DCHECK(quota_io_);
136 if (quota_io_->CheckIfExceedsQuota(length_)) {
137 DidFail(base::PLATFORM_FILE_ERROR_NO_SPACE);
138 return;
139 }
140 quota_io_->WillUpdate();
141 if (is_will_operation_) {
142 DidFinish(base::PLATFORM_FILE_OK);
143 return;
144 }
145 if (!base::FileUtilProxy::Truncate(
146 quota_io_->instance_->delegate()->GetFileThreadMessageLoopProxy(),
147 quota_io_->file_, length_,
148 callback_factory_.NewCallback(&SetLengthOperation::DidFinish))) {
149 DidFail(base::PLATFORM_FILE_ERROR_FAILED);
150 return;
151 }
152 }
153
154 virtual void DidFail(PlatformFileError error) OVERRIDE {
155 DidFinish(error);
156 }
157
158 private:
159 void DidFinish(PlatformFileError status) {
160 quota_io_->DidSetLength(status != base::PLATFORM_FILE_OK ? -1 : length_);
161 quota_io_->UnregisterOperation(this);
162 DCHECK(callback_.get());
163 callback_->Run(status);
164 callback_.reset();
165 delete this;
166 }
167
168 int64_t length_;
169 scoped_ptr<StatusCallback> callback_;
170 base::ScopedCallbackFactory<QuotaFileIO::SetLengthOperation>
171 callback_factory_;
172 };
173
174 // QuotaFileIO --------------------------------------------------------------
175
176 QuotaFileIO::QuotaFileIO(
177 PluginInstance* instance,
178 PlatformFile file,
179 const GURL& file_url,
180 PP_FileSystemType type)
181 : instance_(instance),
182 file_(file),
183 file_url_(file_url),
184 storage_type_(PPFileSystemTypeToQuotaStorageType(type)),
185 cached_file_size_(0),
186 cached_available_space_(0),
187 outstanding_quota_queries_(0),
188 outstanding_errors_(0),
189 did_notify_will_update_(false),
190 max_written_offset_(0),
191 callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
192 DCHECK(instance_);
193 DCHECK_NE(base::kInvalidPlatformFileValue, file_);
194 DCHECK_NE(quota::kStorageTypeUnknown, storage_type_);
195 }
196
197 QuotaFileIO::~QuotaFileIO() {
198 STLDeleteContainerPointers(registered_operations_.begin(),
199 registered_operations_.end());
200 }
201
202 bool QuotaFileIO::Write(
203 int64_t offset, const char* buffer, int32_t bytes_to_write,
204 WriteCallback* callback) {
205 WriteOperation* op = new WriteOperation(
206 this, false, offset, buffer, bytes_to_write, callback);
207 return RegisterOperationForQuotaChecks(op);
208 }
209
210 bool QuotaFileIO::SetLength(int64_t length, StatusCallback* callback) {
211 DCHECK(pending_operations_.empty());
212 SetLengthOperation* op = new SetLengthOperation(
213 this, false, length, callback);
214 return RegisterOperationForQuotaChecks(op);
215 }
216
217 bool QuotaFileIO::WillWrite(
218 int64_t offset, int32_t bytes_to_write, WriteCallback* callback) {
219 WriteOperation* op = new WriteOperation(
220 this, true, offset, NULL, bytes_to_write, callback);
221 return RegisterOperationForQuotaChecks(op);
222 }
223
224 bool QuotaFileIO::WillSetLength(int64_t length, StatusCallback* callback) {
225 DCHECK(pending_operations_.empty());
226 SetLengthOperation* op = new SetLengthOperation(this, true, length, callback);
227 return RegisterOperationForQuotaChecks(op);
228 }
229
230 bool QuotaFileIO::RegisterOperationForQuotaChecks(
231 PendingOperationBase* op_ptr) {
232 scoped_ptr<PendingOperationBase> op(op_ptr);
233 if (pending_operations_.empty()) {
234 // This is the first pending quota check. Run querying the file size
235 // and available space.
236 outstanding_quota_queries_ = 0;
237 outstanding_errors_ = 0;
238
239 // Query the file size.
240 ++outstanding_quota_queries_;
241 if (!base::FileUtilProxy::GetFileInfoFromPlatformFile(
242 instance_->delegate()->GetFileThreadMessageLoopProxy(), file_,
243 callback_factory_.NewCallback(&QuotaFileIO::DidQueryInfoForQuota)))
244 return false;
brettw 2011/07/26 16:40:14 Can you add a comment here that the op_ptr destruc
kinuko 2011/07/27 09:33:14 Changed to explicitly call DidFail.
245
246 // Query the current available space.
247 ++outstanding_quota_queries_;
248 instance_->delegate()->QueryAvailableSpace(
249 GURL(file_url_.path()).GetOrigin(), storage_type_,
250 callback_factory_.NewCallback(&QuotaFileIO::DidQueryAvailableSpace));
251 }
252 pending_operations_.push(op.release());
253 return true;
254 }
255
256 void QuotaFileIO::DidQueryInfoForQuota(
257 base::PlatformFileError error_code,
258 const base::PlatformFileInfo& file_info) {
259 if (error_code != base::PLATFORM_FILE_OK)
260 ++outstanding_errors_;
261 cached_file_size_ = file_info.size;
262 DCHECK_GT(outstanding_quota_queries_, 0);
263 if (--outstanding_quota_queries_ == 0)
264 DidQueryForQuotaCheck();
265 }
266
267 void QuotaFileIO::DidQueryAvailableSpace(int64_t avail_space) {
268 cached_available_space_ = avail_space;
269 DCHECK_GT(outstanding_quota_queries_, 0);
270 if (--outstanding_quota_queries_ == 0)
271 DidQueryForQuotaCheck();
272 }
273
274 void QuotaFileIO::DidQueryForQuotaCheck() {
275 DCHECK(!pending_operations_.empty());
276 while (!pending_operations_.empty()) {
277 PendingOperationBase* op = pending_operations_.front();
278 pending_operations_.pop();
279 if (outstanding_errors_ > 0) {
280 op->DidFail(base::PLATFORM_FILE_ERROR_FAILED);
281 continue;
282 }
283 op->Run();
284 }
285 }
286
287 bool QuotaFileIO::CheckIfExceedsQuota(int64_t new_file_size) const {
288 DCHECK_GE(cached_file_size_, 0);
289 DCHECK_GE(cached_available_space_, 0);
290 return new_file_size - cached_file_size_ > cached_available_space_;
291 }
292
293 void QuotaFileIO::WillUpdate() {
294 if (!did_notify_will_update_) {
295 instance_->delegate()->WillUpdateFile(file_url_);
296 did_notify_will_update_ = true;
297 DCHECK_EQ(0, max_written_offset_);
298 }
299 }
300
301 void QuotaFileIO::DidWrite(int64_t written_offset_end) {
302 max_written_offset_ = std::max(max_written_offset_, written_offset_end);
303 DCHECK(did_notify_will_update_);
304 // If we have no more pending writes, notify the browser that we did
305 // update the file.
306 if (registered_operations_.size() == 1) {
307 int64_t growth = max_written_offset_ - cached_file_size_;
308 growth = growth < 0 ? 0 : growth;
309 instance_->delegate()->DidUpdateFile(file_url_, growth);
310 did_notify_will_update_ = false;
311 max_written_offset_ = 0;
312 }
313 }
314
315 void QuotaFileIO::DidSetLength(int64_t new_file_size) {
316 DCHECK(did_notify_will_update_);
317 int64_t delta = new_file_size >= 0 ? new_file_size - cached_file_size_ : 0;
318 instance_->delegate()->DidUpdateFile(file_url_, delta);
319 did_notify_will_update_ = false;
320 }
321
322 void QuotaFileIO::RegisterOperation(PendingOperationBase* operation) {
323 registered_operations_.insert(operation);
324 }
325
326 void QuotaFileIO::UnregisterOperation(PendingOperationBase* op) {
327 DCHECK(registered_operations_.find(op) != registered_operations_.end());
328 registered_operations_.erase(op);
329 }
330
331 } // namespace ppapi
332 } // namespace webkit
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698