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

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: fix 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_->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 buffer_(buffer),
62 bytes_to_write_(bytes_to_write),
63 callback_(callback),
64 status_(base::PLATFORM_FILE_OK),
65 bytes_written_(0),
66 callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {}
67 virtual ~WriteOperation() {}
68 virtual void Run() OVERRIDE {
69 DCHECK(quota_io_);
70 if (quota_io_->CheckIfExceedsQuota(offset_ + bytes_to_write_)) {
71 DidFail(base::PLATFORM_FILE_ERROR_NO_SPACE);
72 return;
73 }
74 if (is_will_operation_) {
75 // Assuming the write will succeed.
76 DidFinish(base::PLATFORM_FILE_OK, bytes_to_write_);
77 return;
78 }
79 DCHECK(buffer_);
80 if (!base::FileUtilProxy::Write(
81 quota_io_->instance_->delegate()->GetFileThreadMessageLoopProxy(),
82 quota_io_->file_, offset_, buffer_, bytes_to_write_,
83 callback_factory_.NewCallback(&WriteOperation::DidFinish))) {
84 DidFail(base::PLATFORM_FILE_ERROR_FAILED);
85 return;
86 }
87 }
88
89 virtual void DidFail(PlatformFileError error) OVERRIDE {
90 DidFinish(error, 0);
91 }
92
93 void RunCallback() {
94 DCHECK(callback_.get());
95 callback_->Run(status_, bytes_written_);
96 callback_.reset();
97 delete this;
98 }
99
100 private:
101 void DidFinish(PlatformFileError status, int bytes_written) {
102 status_ = status;
103 bytes_written_ = bytes_written;
104 int64_t max_offset =
105 (status != base::PLATFORM_FILE_OK) ? 0 : offset_ + bytes_written;
106 // This may delete itself by calling RunCallback.
107 quota_io_->DidWrite(this, max_offset);
108 }
109
110 const int64_t offset_;
111 const char* buffer_;
112 const int32_t bytes_to_write_;
113 scoped_ptr<WriteCallback> callback_;
114 PlatformFileError status_;
115 int64_t bytes_written_;
116 base::ScopedCallbackFactory<QuotaFileIO::WriteOperation> callback_factory_;
117 };
118
119 class QuotaFileIO::SetLengthOperation : public PendingOperationBase {
120 public:
121 SetLengthOperation(QuotaFileIO* quota_io,
122 bool is_will_operation,
123 int64_t length,
124 StatusCallback* callback)
125 : PendingOperationBase(quota_io, is_will_operation),
126 length_(length),
127 callback_(callback),
128 callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {}
129 virtual ~SetLengthOperation() {}
130
131 virtual void Run() OVERRIDE {
132 DCHECK(quota_io_);
133 if (quota_io_->CheckIfExceedsQuota(length_)) {
134 DidFail(base::PLATFORM_FILE_ERROR_NO_SPACE);
135 return;
136 }
137 if (is_will_operation_) {
138 DidFinish(base::PLATFORM_FILE_OK);
139 return;
140 }
141 if (!base::FileUtilProxy::Truncate(
142 quota_io_->instance_->delegate()->GetFileThreadMessageLoopProxy(),
143 quota_io_->file_, length_,
144 callback_factory_.NewCallback(&SetLengthOperation::DidFinish))) {
145 DidFail(base::PLATFORM_FILE_ERROR_FAILED);
146 return;
147 }
148 }
149
150 virtual void DidFail(PlatformFileError error) OVERRIDE {
151 DidFinish(error);
152 }
153
154 private:
155 void DidFinish(PlatformFileError status) {
156 quota_io_->DidSetLength(status, length_);
157 DCHECK(callback_.get());
158 callback_->Run(status);
159 callback_.reset();
160 delete this;
161 }
162
163 int64_t length_;
164 scoped_ptr<StatusCallback> callback_;
165 base::ScopedCallbackFactory<QuotaFileIO::SetLengthOperation>
166 callback_factory_;
167 };
168
169 // QuotaFileIO --------------------------------------------------------------
170
171 QuotaFileIO::QuotaFileIO(
172 PluginInstance* instance,
173 PlatformFile file,
174 const GURL& file_url,
175 PP_FileSystemType type)
176 : instance_(instance),
177 file_(file),
178 file_url_(file_url),
179 storage_type_(PPFileSystemTypeToQuotaStorageType(type)),
180 cached_file_size_(0),
181 cached_available_space_(0),
182 outstanding_quota_queries_(0),
183 outstanding_errors_(0),
184 max_written_offset_(0),
185 inflight_operations_(0),
186 callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
187 DCHECK(instance_);
188 DCHECK_NE(base::kInvalidPlatformFileValue, file_);
189 DCHECK_NE(quota::kStorageTypeUnknown, storage_type_);
190 }
191
192 QuotaFileIO::~QuotaFileIO() {
193 // Note that this doesn't dispatch pending callbacks.
194 STLDeleteContainerPointers(pending_operations_.begin(),
195 pending_operations_.end());
196 STLDeleteContainerPointers(pending_callbacks_.begin(),
197 pending_callbacks_.end());
198 }
199
200 bool QuotaFileIO::Write(
201 int64_t offset, const char* buffer, int32_t bytes_to_write,
202 WriteCallback* callback) {
203 WriteOperation* op = new WriteOperation(
204 this, false, offset, buffer, bytes_to_write, callback);
205 return RegisterOperationForQuotaChecks(op);
206 }
207
208 bool QuotaFileIO::SetLength(int64_t length, StatusCallback* callback) {
209 DCHECK(pending_operations_.empty());
210 SetLengthOperation* op = new SetLengthOperation(
211 this, false, length, callback);
212 return RegisterOperationForQuotaChecks(op);
213 }
214
215 bool QuotaFileIO::WillWrite(
216 int64_t offset, int32_t bytes_to_write, WriteCallback* callback) {
217 WriteOperation* op = new WriteOperation(
218 this, true, offset, NULL, bytes_to_write, callback);
219 return RegisterOperationForQuotaChecks(op);
220 }
221
222 bool QuotaFileIO::WillSetLength(int64_t length, StatusCallback* callback) {
223 DCHECK(pending_operations_.empty());
224 SetLengthOperation* op = new SetLengthOperation(this, true, length, callback);
225 return RegisterOperationForQuotaChecks(op);
226 }
227
228 bool QuotaFileIO::RegisterOperationForQuotaChecks(
229 PendingOperationBase* op_ptr) {
230 scoped_ptr<PendingOperationBase> op(op_ptr);
231 if (pending_operations_.empty()) {
232 // This is the first pending quota check. Run querying the file size
233 // and available space.
234 outstanding_quota_queries_ = 0;
235 outstanding_errors_ = 0;
236
237 // Query the file size.
238 ++outstanding_quota_queries_;
239 if (!base::FileUtilProxy::GetFileInfoFromPlatformFile(
240 instance_->delegate()->GetFileThreadMessageLoopProxy(), file_,
241 callback_factory_.NewCallback(
242 &QuotaFileIO::DidQueryInfoForQuota))) {
243 // This makes the call fail synchronously; we do not fire the callback
244 // here but just delete the operation and return false.
245 return false;
246 }
247
248 // Query the current available space.
249 ++outstanding_quota_queries_;
250 instance_->delegate()->QueryAvailableSpace(
251 GURL(file_url_.path()).GetOrigin(), storage_type_,
252 callback_factory_.NewCallback(&QuotaFileIO::DidQueryAvailableSpace));
253 }
254 pending_operations_.push_back(op.release());
255 return true;
256 }
257
258 void QuotaFileIO::DidQueryInfoForQuota(
259 base::PlatformFileError error_code,
260 const base::PlatformFileInfo& file_info) {
261 if (error_code != base::PLATFORM_FILE_OK)
262 ++outstanding_errors_;
263 cached_file_size_ = file_info.size;
264 DCHECK_GT(outstanding_quota_queries_, 0);
265 if (--outstanding_quota_queries_ == 0)
266 DidQueryForQuotaCheck();
267 }
268
269 void QuotaFileIO::DidQueryAvailableSpace(int64_t avail_space) {
270 cached_available_space_ = avail_space;
271 DCHECK_GT(outstanding_quota_queries_, 0);
272 if (--outstanding_quota_queries_ == 0)
273 DidQueryForQuotaCheck();
274 }
275
276 void QuotaFileIO::DidQueryForQuotaCheck() {
277 DCHECK(!pending_operations_.empty());
278 DCHECK_GT(inflight_operations_, 0);
279 while (!pending_operations_.empty()) {
280 PendingOperationBase* op = pending_operations_.front();
281 pending_operations_.pop_front();
282 pending_callbacks_.push_back(op);
283 if (outstanding_errors_ > 0) {
284 op->DidFail(base::PLATFORM_FILE_ERROR_FAILED);
285 continue;
286 }
287 op->Run();
288 }
289 }
290
291 bool QuotaFileIO::CheckIfExceedsQuota(int64_t new_file_size) const {
292 DCHECK_GE(cached_file_size_, 0);
293 DCHECK_GE(cached_available_space_, 0);
294 return new_file_size - cached_file_size_ > cached_available_space_;
295 }
296
297 void QuotaFileIO::WillUpdate() {
298 if (inflight_operations_++ == 0) {
299 instance_->delegate()->WillUpdateFile(file_url_);
300 DCHECK_EQ(0, max_written_offset_);
301 }
302 }
303
304 void QuotaFileIO::DidWrite(WriteOperation* op,
305 int64_t written_offset_end) {
306 max_written_offset_ = std::max(max_written_offset_, written_offset_end);
307 DCHECK_GT(inflight_operations_, 0);
308 // If we have no more pending writes, notify the browser that we did
309 // update the file.
310 if (--inflight_operations_ == 0) {
yzshen1 2011/07/27 18:26:08 This seems bad to me: we only fire callbacks when
kinuko 2011/07/28 14:11:00 Yes 1) sounds better to me too and I had wondered
yzshen1 2011/07/28 17:40:52 It looks better now! Thanks. On 2011/07/28 14:11:
311 // Callbacks need to be fired in order.
312 while (!pending_callbacks_.empty()) {
313 WriteOperation* op = static_cast<WriteOperation*>(
314 pending_callbacks_.front());
315 op->RunCallback();
316 pending_callbacks_.pop_front();
317 }
318 int64_t growth = max_written_offset_ - cached_file_size_;
319 growth = growth < 0 ? 0 : growth;
320 instance_->delegate()->DidUpdateFile(file_url_, growth);
321 max_written_offset_ = 0;
322 }
323 }
324
325 void QuotaFileIO::DidSetLength(PlatformFileError error, int64_t new_file_size) {
326 DCHECK_EQ(1, inflight_operations_);
327 DCHECK_EQ(1U, pending_callbacks_.size());
328 pending_callbacks_.clear();
329 int64_t delta = (error != base::PLATFORM_FILE_OK) ? 0 :
330 new_file_size - cached_file_size_;
331 instance_->delegate()->DidUpdateFile(file_url_, delta);
332 inflight_operations_ = 0;
333 }
334
335 } // namespace ppapi
336 } // namespace webkit
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698