OLD | NEW |
---|---|
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 "net/disk_cache/simple/simple_entry_impl.h" | 5 #include "net/disk_cache/simple/simple_entry_impl.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/bind_helpers.h" | 8 #include "base/bind_helpers.h" |
9 #include "base/callback.h" | 9 #include "base/callback.h" |
10 #include "base/location.h" | 10 #include "base/location.h" |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
81 index->Remove(key); | 81 index->Remove(key); |
82 WorkerPool::PostTask(FROM_HERE, | 82 WorkerPool::PostTask(FROM_HERE, |
83 base::Bind(&SimpleSynchronousEntry::DoomEntry, path, key, | 83 base::Bind(&SimpleSynchronousEntry::DoomEntry, path, key, |
84 MessageLoopProxy::current(), callback), | 84 MessageLoopProxy::current(), callback), |
85 true); | 85 true); |
86 return net::ERR_IO_PENDING; | 86 return net::ERR_IO_PENDING; |
87 } | 87 } |
88 | 88 |
89 void SimpleEntryImpl::Doom() { | 89 void SimpleEntryImpl::Doom() { |
90 DCHECK(io_thread_checker_.CalledOnValidThread()); | 90 DCHECK(io_thread_checker_.CalledOnValidThread()); |
91 DCHECK(!operation_running_); | |
91 #if defined(OS_POSIX) | 92 #if defined(OS_POSIX) |
92 // This call to static SimpleEntryImpl::DoomEntry() will just erase the | 93 // This call to static SimpleEntryImpl::DoomEntry() will just erase the |
93 // underlying files. On POSIX, this is fine; the files are still open on the | 94 // underlying files. On POSIX, this is fine; the files are still open on the |
94 // SimpleSynchronousEntry, and operations can even happen on them. The files | 95 // SimpleSynchronousEntry, and operations can even happen on them. The files |
95 // will be removed from the filesystem when they are closed. | 96 // will be removed from the filesystem when they are closed. |
96 DoomEntry(index_, path_, key_, CompletionCallback()); | 97 DoomEntry(index_, path_, key_, CompletionCallback()); |
97 #else | 98 #else |
98 NOTIMPLEMENTED(); | 99 NOTIMPLEMENTED(); |
99 #endif | 100 #endif |
100 } | 101 } |
101 | 102 |
102 void SimpleEntryImpl::Close() { | 103 void SimpleEntryImpl::Close() { |
103 DCHECK(io_thread_checker_.CalledOnValidThread()); | 104 DCHECK(io_thread_checker_.CalledOnValidThread()); |
104 if (!synchronous_entry_in_use_by_worker_) { | 105 if (operation_running_) { |
105 WorkerPool::PostTask(FROM_HERE, | 106 // Postpone close operation. |
106 base::Bind(&SimpleSynchronousEntry::Close, | 107 // Push the close operation to the end of the line. This way we run all |
107 base::Unretained(synchronous_entry_)), | 108 // operations before we are able close. |
108 true); | 109 pending_operations_.push( |
110 base::Bind(&SimpleEntryImpl::Close, | |
111 weak_ptr_factory_.GetWeakPtr())); | |
112 return; | |
pasko-google - do not use
2013/04/17 15:14:46
since it is not a trivial if->return case, would b
felipeg
2013/04/17 15:53:57
Done.
| |
109 } | 113 } |
114 DCHECK(pending_operations_.size() == 0); | |
115 DCHECK(!operation_running_); | |
116 | |
117 WorkerPool::PostTask(FROM_HERE, | |
118 base::Bind(&SimpleSynchronousEntry::Close, | |
119 base::Unretained(synchronous_entry_)), | |
120 true); | |
110 // Entry::Close() is expected to release this entry. See disk_cache.h for | 121 // Entry::Close() is expected to release this entry. See disk_cache.h for |
111 // details. | 122 // details. |
112 delete this; | 123 delete this; |
113 } | 124 } |
114 | 125 |
115 std::string SimpleEntryImpl::GetKey() const { | 126 std::string SimpleEntryImpl::GetKey() const { |
116 DCHECK(io_thread_checker_.CalledOnValidThread()); | 127 DCHECK(io_thread_checker_.CalledOnValidThread()); |
117 return key_; | 128 return key_; |
118 } | 129 } |
119 | 130 |
(...skipping 11 matching lines...) Expand all Loading... | |
131 DCHECK(io_thread_checker_.CalledOnValidThread()); | 142 DCHECK(io_thread_checker_.CalledOnValidThread()); |
132 return data_size_[index]; | 143 return data_size_[index]; |
133 } | 144 } |
134 | 145 |
135 int SimpleEntryImpl::ReadData(int index, | 146 int SimpleEntryImpl::ReadData(int index, |
136 int offset, | 147 int offset, |
137 net::IOBuffer* buf, | 148 net::IOBuffer* buf, |
138 int buf_len, | 149 int buf_len, |
139 const CompletionCallback& callback) { | 150 const CompletionCallback& callback) { |
140 DCHECK(io_thread_checker_.CalledOnValidThread()); | 151 DCHECK(io_thread_checker_.CalledOnValidThread()); |
141 // TODO(gavinp): Add support for overlapping reads. The net::HttpCache does | 152 if (index < 0 || index >= kSimpleEntryFileCount || buf_len < 0) |
pasko-google - do not use
2013/04/17 15:14:46
was this requested by tests?
Otherwise seems like
felipeg
2013/04/17 15:53:57
Done.
| |
142 // make overlapping read requests when multiple transactions access the same | 153 return net::ERR_INVALID_ARGUMENT; |
143 // entry as read only. This might make calling SimpleSynchronousEntry::Close() | 154 if (offset >= data_size_[index] || offset < 0 || !buf_len) |
144 // correctly more tricky (see SimpleEntryImpl::EntryOperationComplete). | 155 return 0; |
145 if (synchronous_entry_in_use_by_worker_) { | 156 // TODO(felipeg): Optimization: Add support for truly parallel read |
146 NOTIMPLEMENTED(); | 157 // operations. |
147 CHECK(false); | 158 pending_operations_.push( |
148 } | 159 base::Bind(&SimpleEntryImpl::ReadDataInternal, |
149 synchronous_entry_in_use_by_worker_ = true; | 160 weak_ptr_factory_.GetWeakPtr(), |
150 if (index_) | 161 index, |
151 index_->UseIfExists(key_); | 162 offset, |
152 SynchronousOperationCallback sync_operation_callback = | 163 make_scoped_refptr(buf), |
153 base::Bind(&SimpleEntryImpl::EntryOperationComplete, | 164 buf_len, |
154 index_, callback, weak_ptr_factory_.GetWeakPtr(), | 165 callback)); |
155 synchronous_entry_); | 166 RunNextOperationIfNeeded(); |
156 WorkerPool::PostTask(FROM_HERE, | |
157 base::Bind(&SimpleSynchronousEntry::ReadData, | |
158 base::Unretained(synchronous_entry_), | |
159 index, offset, make_scoped_refptr(buf), | |
160 buf_len, sync_operation_callback), | |
161 true); | |
162 return net::ERR_IO_PENDING; | 167 return net::ERR_IO_PENDING; |
163 } | 168 } |
164 | 169 |
165 int SimpleEntryImpl::WriteData(int index, | 170 int SimpleEntryImpl::WriteData(int index, |
166 int offset, | 171 int offset, |
167 net::IOBuffer* buf, | 172 net::IOBuffer* buf, |
168 int buf_len, | 173 int buf_len, |
169 const CompletionCallback& callback, | 174 const CompletionCallback& callback, |
170 bool truncate) { | 175 bool truncate) { |
171 DCHECK(io_thread_checker_.CalledOnValidThread()); | 176 DCHECK(io_thread_checker_.CalledOnValidThread()); |
172 if (synchronous_entry_in_use_by_worker_) { | 177 if (index < 0 || index >= kSimpleEntryFileCount || offset < 0 || buf_len < 0) |
173 NOTIMPLEMENTED(); | 178 return net::ERR_INVALID_ARGUMENT; |
174 CHECK(false); | 179 |
175 } | 180 pending_operations_.push( |
176 synchronous_entry_in_use_by_worker_ = true; | 181 base::Bind(&SimpleEntryImpl::WriteDataInternal, |
177 if (index_) | 182 weak_ptr_factory_.GetWeakPtr(), |
178 index_->UseIfExists(key_); | 183 index, |
179 SynchronousOperationCallback sync_operation_callback = | 184 offset, |
180 base::Bind(&SimpleEntryImpl::EntryOperationComplete, | 185 make_scoped_refptr(buf), |
181 index_, callback, weak_ptr_factory_.GetWeakPtr(), | 186 buf_len, |
182 synchronous_entry_); | 187 callback, |
183 WorkerPool::PostTask(FROM_HERE, | 188 truncate)); |
184 base::Bind(&SimpleSynchronousEntry::WriteData, | 189 RunNextOperationIfNeeded(); |
185 base::Unretained(synchronous_entry_), | 190 |
186 index, offset, make_scoped_refptr(buf), | 191 // TODO(felipeg): Optimization: Add support for optimistic writes, quickly |
187 buf_len, sync_operation_callback, truncate), | 192 // returning net::OK here. |
188 true); | |
189 return net::ERR_IO_PENDING; | 193 return net::ERR_IO_PENDING; |
190 } | 194 } |
191 | 195 |
192 int SimpleEntryImpl::ReadSparseData(int64 offset, | 196 int SimpleEntryImpl::ReadSparseData(int64 offset, |
193 net::IOBuffer* buf, | 197 net::IOBuffer* buf, |
194 int buf_len, | 198 int buf_len, |
195 const CompletionCallback& callback) { | 199 const CompletionCallback& callback) { |
196 DCHECK(io_thread_checker_.CalledOnValidThread()); | 200 DCHECK(io_thread_checker_.CalledOnValidThread()); |
197 // TODO(gavinp): Determine if the simple backend should support sparse data. | 201 // TODO(gavinp): Determine if the simple backend should support sparse data. |
198 NOTIMPLEMENTED(); | 202 NOTIMPLEMENTED(); |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
238 return net::ERR_FAILED; | 242 return net::ERR_FAILED; |
239 } | 243 } |
240 | 244 |
241 SimpleEntryImpl::SimpleEntryImpl( | 245 SimpleEntryImpl::SimpleEntryImpl( |
242 SimpleSynchronousEntry* synchronous_entry, | 246 SimpleSynchronousEntry* synchronous_entry, |
243 WeakPtr<SimpleIndex> index) | 247 WeakPtr<SimpleIndex> index) |
244 : ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)), | 248 : ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)), |
245 path_(synchronous_entry->path()), | 249 path_(synchronous_entry->path()), |
246 key_(synchronous_entry->key()), | 250 key_(synchronous_entry->key()), |
247 synchronous_entry_(synchronous_entry), | 251 synchronous_entry_(synchronous_entry), |
248 synchronous_entry_in_use_by_worker_(false), | 252 operation_running_(false), |
249 index_(index) { | 253 index_(index) { |
250 DCHECK(synchronous_entry); | 254 DCHECK(synchronous_entry); |
251 SetSynchronousData(); | 255 SetSynchronousData(); |
252 } | 256 } |
253 | 257 |
254 SimpleEntryImpl::~SimpleEntryImpl() { | 258 SimpleEntryImpl::~SimpleEntryImpl() { |
255 DCHECK(io_thread_checker_.CalledOnValidThread()); | 259 DCHECK(io_thread_checker_.CalledOnValidThread()); |
256 } | 260 } |
257 | 261 |
262 bool SimpleEntryImpl::RunNextOperationIfNeeded() { | |
263 DCHECK(io_thread_checker_.CalledOnValidThread()); | |
264 if (pending_operations_.size() <= 0 || operation_running_) | |
265 return false; | |
266 base::Closure operation = pending_operations_.front(); | |
267 pending_operations_.pop(); | |
268 operation.Run(); | |
269 return true; | |
270 } | |
271 | |
272 void SimpleEntryImpl::ReadDataInternal(int index, | |
273 int offset, | |
274 scoped_refptr<net::IOBuffer> buf, | |
275 int buf_len, | |
276 const CompletionCallback& callback) { | |
277 DCHECK(io_thread_checker_.CalledOnValidThread()); | |
278 DCHECK(!operation_running_); | |
279 operation_running_ = true; | |
280 if (index_) | |
281 index_->UseIfExists(key_); | |
282 SynchronousOperationCallback sync_operation_callback = | |
283 base::Bind(&SimpleEntryImpl::EntryOperationComplete, | |
284 index_, callback, weak_ptr_factory_.GetWeakPtr(), | |
285 synchronous_entry_); | |
286 WorkerPool::PostTask(FROM_HERE, | |
287 base::Bind(&SimpleSynchronousEntry::ReadData, | |
288 base::Unretained(synchronous_entry_), | |
289 index, offset, buf, | |
290 buf_len, sync_operation_callback), | |
291 true); | |
292 } | |
293 | |
294 void SimpleEntryImpl::WriteDataInternal(int index, | |
295 int offset, | |
296 scoped_refptr<net::IOBuffer> buf, | |
297 int buf_len, | |
298 const CompletionCallback& callback, | |
299 bool truncate) { | |
300 DCHECK(io_thread_checker_.CalledOnValidThread()); | |
301 DCHECK(!operation_running_); | |
302 operation_running_ = true; | |
303 if (index_) | |
304 index_->UseIfExists(key_); | |
305 | |
306 last_used_ = base::Time::Now(); | |
307 last_modified_ = base::Time::Now(); | |
308 data_size_[index] = buf_len; | |
309 | |
310 SynchronousOperationCallback sync_operation_callback = | |
311 base::Bind(&SimpleEntryImpl::EntryOperationComplete, | |
312 index_, callback, weak_ptr_factory_.GetWeakPtr(), | |
313 synchronous_entry_); | |
314 WorkerPool::PostTask(FROM_HERE, | |
315 base::Bind(&SimpleSynchronousEntry::WriteData, | |
316 base::Unretained(synchronous_entry_), | |
317 index, offset, buf, | |
318 buf_len, sync_operation_callback, truncate), | |
319 true); | |
320 } | |
321 | |
258 // static | 322 // static |
259 void SimpleEntryImpl::CreationOperationComplete( | 323 void SimpleEntryImpl::CreationOperationComplete( |
260 WeakPtr<SimpleIndex> index, | 324 WeakPtr<SimpleIndex> index, |
261 const CompletionCallback& completion_callback, | 325 const CompletionCallback& completion_callback, |
262 const std::string& key, | 326 const std::string& key, |
263 Entry** out_entry, | 327 Entry** out_entry, |
264 SimpleSynchronousEntry* sync_entry) { | 328 SimpleSynchronousEntry* sync_entry) { |
265 if (!sync_entry) { | 329 if (!sync_entry) { |
266 completion_callback.Run(net::ERR_FAILED); | 330 completion_callback.Run(net::ERR_FAILED); |
267 // If OpenEntry failed, we must remove it from our index. | 331 // If OpenEntry failed, we must remove it from our index. |
(...skipping 16 matching lines...) Expand all Loading... | |
284 int result) { | 348 int result) { |
285 DCHECK(sync_entry); | 349 DCHECK(sync_entry); |
286 if (index) { | 350 if (index) { |
287 if (result >= 0) | 351 if (result >= 0) |
288 index->UpdateEntrySize(sync_entry->key(), sync_entry->GetFileSize()); | 352 index->UpdateEntrySize(sync_entry->key(), sync_entry->GetFileSize()); |
289 else | 353 else |
290 index->Remove(sync_entry->key()); | 354 index->Remove(sync_entry->key()); |
291 } | 355 } |
292 | 356 |
293 if (entry) { | 357 if (entry) { |
294 DCHECK(entry->synchronous_entry_in_use_by_worker_); | 358 DCHECK(entry->operation_running_); |
295 entry->synchronous_entry_in_use_by_worker_ = false; | 359 entry->operation_running_ = false; |
296 entry->SetSynchronousData(); | 360 entry->SetSynchronousData(); |
361 entry->RunNextOperationIfNeeded(); | |
297 } else { | 362 } else { |
298 // |entry| must have had Close() called while this operation was in flight. | 363 // |entry| must have had Close() called while this operation was in flight. |
299 // Since the simple cache now only supports one pending entry operation in | 364 // Since the simple cache now only supports one pending entry operation in |
300 // flight at a time, it's safe to now call Close() on |sync_entry|. | 365 // flight at a time, it's safe to now call Close() on |sync_entry|. |
301 WorkerPool::PostTask(FROM_HERE, | 366 WorkerPool::PostTask(FROM_HERE, |
302 base::Bind(&SimpleSynchronousEntry::Close, | 367 base::Bind(&SimpleSynchronousEntry::Close, |
303 base::Unretained(sync_entry)), | 368 base::Unretained(sync_entry)), |
304 true); | 369 true); |
305 } | 370 } |
306 completion_callback.Run(result); | 371 completion_callback.Run(result); |
307 } | 372 } |
308 | 373 |
309 void SimpleEntryImpl::SetSynchronousData() { | 374 void SimpleEntryImpl::SetSynchronousData() { |
310 DCHECK(io_thread_checker_.CalledOnValidThread()); | 375 DCHECK(io_thread_checker_.CalledOnValidThread()); |
311 DCHECK(!synchronous_entry_in_use_by_worker_); | 376 DCHECK(!operation_running_); |
312 // TODO(felipeg): These copies to avoid data races are not optimal. While | 377 // TODO(felipeg): These copies to avoid data races are not optimal. While |
313 // adding an IO thread index (for fast misses etc...), we can store this data | 378 // adding an IO thread index (for fast misses etc...), we can store this data |
314 // in that structure. This also solves problems with last_used() on ext4 | 379 // in that structure. This also solves problems with last_used() on ext4 |
315 // filesystems not being accurate. | 380 // filesystems not being accurate. |
316 last_used_ = synchronous_entry_->last_used(); | 381 last_used_ = synchronous_entry_->last_used(); |
317 last_modified_ = synchronous_entry_->last_modified(); | 382 last_modified_ = synchronous_entry_->last_modified(); |
318 for (int i = 0; i < kSimpleEntryFileCount; ++i) | 383 for (int i = 0; i < kSimpleEntryFileCount; ++i) |
319 data_size_[i] = synchronous_entry_->data_size(i); | 384 data_size_[i] = synchronous_entry_->data_size(i); |
320 } | 385 } |
321 | 386 |
322 } // namespace disk_cache | 387 } // namespace disk_cache |
OLD | NEW |