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 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
79 const CompletionCallback& callback) { | 79 const CompletionCallback& callback) { |
80 if (index) | 80 if (index) |
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() { |
gavinp
2013/04/17 08:12:35
I think doom is one of the only operations that al
felipeg
2013/04/17 10:06:43
Done.
| |
90 LOG(INFO) << " DOOM " << key_; | |
90 DCHECK(io_thread_checker_.CalledOnValidThread()); | 91 DCHECK(io_thread_checker_.CalledOnValidThread()); |
92 if (synchronous_entry_in_use_by_worker_) { | |
93 // Postpone doom operation. | |
94 operations_.push( | |
95 base::Bind(&SimpleEntryImpl::DoomInternal, | |
96 weak_ptr_factory_.GetWeakPtr())); | |
97 return; | |
98 } | |
99 DCHECK(operations_.size() == 0); | |
100 DCHECK(!synchronous_entry_in_use_by_worker_); | |
101 | |
102 DoomInternal(); | |
103 // TODO(felipeg): Maybe we should have a flag is_doomed_ and do some DCHECKS | |
104 // around the code, to see if we dont call read in a doomed entry. | |
gavinp
2013/04/17 08:12:35
I believe it's correct and valid to Read/Write in
felipeg
2013/04/17 10:06:43
Done.
| |
105 RunNextOperationIfNeeded(); | |
106 } | |
107 | |
108 void SimpleEntryImpl::DoomInternal() { | |
109 LOG(INFO) << " DOOM " << key_; | |
110 DCHECK(io_thread_checker_.CalledOnValidThread()); | |
111 DCHECK(!synchronous_entry_in_use_by_worker_); | |
91 #if defined(OS_POSIX) | 112 #if defined(OS_POSIX) |
92 // This call to static SimpleEntryImpl::DoomEntry() will just erase the | 113 // 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 | 114 // 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 | 115 // SimpleSynchronousEntry, and operations can even happen on them. The files |
95 // will be removed from the filesystem when they are closed. | 116 // will be removed from the filesystem when they are closed. |
96 DoomEntry(index_, path_, key_, CompletionCallback()); | 117 DoomEntry(index_, path_, key_, CompletionCallback()); |
97 #else | 118 #else |
98 NOTIMPLEMENTED(); | 119 NOTIMPLEMENTED(); |
99 #endif | 120 #endif |
100 } | 121 } |
101 | 122 |
102 void SimpleEntryImpl::Close() { | 123 void SimpleEntryImpl::Close() { |
124 LOG(INFO) << " CLOSE " << key_; | |
103 DCHECK(io_thread_checker_.CalledOnValidThread()); | 125 DCHECK(io_thread_checker_.CalledOnValidThread()); |
104 if (!synchronous_entry_in_use_by_worker_) { | 126 if (synchronous_entry_in_use_by_worker_) { |
105 WorkerPool::PostTask(FROM_HERE, | 127 LOG(INFO) << " CLOSE " << key_; |
106 base::Bind(&SimpleSynchronousEntry::Close, | 128 // Postpone close operation. |
107 base::Unretained(synchronous_entry_)), | 129 // Push the close operation to the end of the line. This way we run all |
108 true); | 130 // operations before we are able close. |
131 operations_.push( | |
132 base::Bind(&SimpleEntryImpl::Close, | |
133 weak_ptr_factory_.GetWeakPtr())); | |
134 return; | |
109 } | 135 } |
136 LOG(INFO) << " CLOSE " << key_; | |
137 DCHECK(operations_.size() == 0); | |
138 DCHECK(!synchronous_entry_in_use_by_worker_); | |
139 | |
140 WorkerPool::PostTask(FROM_HERE, | |
141 base::Bind(&SimpleSynchronousEntry::Close, | |
142 base::Unretained(synchronous_entry_)), | |
143 true); | |
110 // Entry::Close() is expected to release this entry. See disk_cache.h for | 144 // Entry::Close() is expected to release this entry. See disk_cache.h for |
111 // details. | 145 // details. |
112 delete this; | 146 delete this; |
113 } | 147 } |
114 | 148 |
115 std::string SimpleEntryImpl::GetKey() const { | 149 std::string SimpleEntryImpl::GetKey() const { |
116 DCHECK(io_thread_checker_.CalledOnValidThread()); | 150 DCHECK(io_thread_checker_.CalledOnValidThread()); |
117 return key_; | 151 return key_; |
118 } | 152 } |
119 | 153 |
120 Time SimpleEntryImpl::GetLastUsed() const { | 154 Time SimpleEntryImpl::GetLastUsed() const { |
121 DCHECK(io_thread_checker_.CalledOnValidThread()); | 155 DCHECK(io_thread_checker_.CalledOnValidThread()); |
122 return last_used_; | 156 return last_used_; |
123 } | 157 } |
124 | 158 |
125 Time SimpleEntryImpl::GetLastModified() const { | 159 Time SimpleEntryImpl::GetLastModified() const { |
126 DCHECK(io_thread_checker_.CalledOnValidThread()); | 160 DCHECK(io_thread_checker_.CalledOnValidThread()); |
127 return last_modified_; | 161 return last_modified_; |
128 } | 162 } |
129 | 163 |
130 int32 SimpleEntryImpl::GetDataSize(int index) const { | 164 int32 SimpleEntryImpl::GetDataSize(int index) const { |
131 DCHECK(io_thread_checker_.CalledOnValidThread()); | 165 DCHECK(io_thread_checker_.CalledOnValidThread()); |
132 return data_size_[index]; | 166 return data_size_[index]; |
133 } | 167 } |
134 | 168 |
169 | |
170 | |
135 int SimpleEntryImpl::ReadData(int index, | 171 int SimpleEntryImpl::ReadData(int index, |
136 int offset, | 172 int offset, |
137 net::IOBuffer* buf, | 173 net::IOBuffer* buf, |
138 int buf_len, | 174 int buf_len, |
139 const CompletionCallback& callback) { | 175 const CompletionCallback& callback) { |
176 LOG(INFO) << " READ " << key_; | |
140 DCHECK(io_thread_checker_.CalledOnValidThread()); | 177 DCHECK(io_thread_checker_.CalledOnValidThread()); |
141 // TODO(gavinp): Add support for overlapping reads. The net::HttpCache does | 178 // TODO(gavinp): Add support for overlapping reads. The net::HttpCache does |
142 // make overlapping read requests when multiple transactions access the same | 179 // make overlapping read requests when multiple transactions access the same |
143 // entry as read only. This might make calling SimpleSynchronousEntry::Close() | 180 // entry as read only. This might make calling SimpleSynchronousEntry::Close() |
144 // correctly more tricky (see SimpleEntryImpl::EntryOperationComplete). | 181 // correctly more tricky (see SimpleEntryImpl::EntryOperationComplete). |
145 if (synchronous_entry_in_use_by_worker_) { | 182 if (synchronous_entry_in_use_by_worker_ && !read_only_operation_) { |
146 NOTIMPLEMENTED(); | 183 // Postpone read operation. |
147 CHECK(false); | 184 operations_.push( |
185 base::Bind(&SimpleEntryImpl::ReadDataInternal, | |
186 weak_ptr_factory_.GetWeakPtr(), | |
187 index, | |
188 offset, | |
189 make_scoped_refptr(buf), | |
190 buf_len, | |
191 callback)); | |
192 return net::ERR_IO_PENDING; | |
148 } | 193 } |
194 DCHECK(operations_.size() == 0); | |
195 ReadDataInternal(index, | |
196 offset, | |
197 make_scoped_refptr(buf), | |
198 buf_len, | |
199 callback); | |
200 return net::ERR_IO_PENDING; | |
201 } | |
202 | |
203 void SimpleEntryImpl::ReadDataInternal(int index, | |
204 int offset, | |
205 scoped_refptr<net::IOBuffer> buf, | |
206 int buf_len, | |
207 const CompletionCallback& callback) { | |
208 LOG(INFO) << " READ " << key_; | |
209 DCHECK(io_thread_checker_.CalledOnValidThread()); | |
210 DCHECK(!synchronous_entry_in_use_by_worker_); | |
211 read_only_operation_ = true; | |
149 synchronous_entry_in_use_by_worker_ = true; | 212 synchronous_entry_in_use_by_worker_ = true; |
150 if (index_) | 213 if (index_) |
151 index_->UseIfExists(key_); | 214 index_->UseIfExists(key_); |
152 SynchronousOperationCallback sync_operation_callback = | 215 SynchronousOperationCallback sync_operation_callback = |
153 base::Bind(&SimpleEntryImpl::EntryOperationComplete, | 216 base::Bind(&SimpleEntryImpl::EntryOperationComplete, |
154 index_, callback, weak_ptr_factory_.GetWeakPtr(), | 217 index_, callback, weak_ptr_factory_.GetWeakPtr(), |
155 synchronous_entry_); | 218 synchronous_entry_); |
156 WorkerPool::PostTask(FROM_HERE, | 219 WorkerPool::PostTask(FROM_HERE, |
157 base::Bind(&SimpleSynchronousEntry::ReadData, | 220 base::Bind(&SimpleSynchronousEntry::ReadData, |
158 base::Unretained(synchronous_entry_), | 221 base::Unretained(synchronous_entry_), |
159 index, offset, make_scoped_refptr(buf), | 222 index, offset, buf, |
gavinp
2013/04/17 08:17:14
This is really dangerous, calling with the naked b
gavinp
2013/04/17 09:40:16
Boy this stuff is subtle.
I was wrong: I failed t
| |
160 buf_len, sync_operation_callback), | 223 buf_len, sync_operation_callback), |
161 true); | 224 true); |
162 return net::ERR_IO_PENDING; | 225 } |
226 | |
227 // TODO(felipeg): Maybe in case of failure from a write operation, we could try | |
228 // to invalidate all operations in the queue of the current entry. | |
229 static void WriteDataNoOp(int noop) { | |
163 } | 230 } |
164 | 231 |
165 int SimpleEntryImpl::WriteData(int index, | 232 int SimpleEntryImpl::WriteData(int index, |
gavinp
2013/04/17 09:23:56
I think ReadData / WriteData can be made a lot sim
felipeg
2013/04/17 10:06:43
Done.
| |
166 int offset, | 233 int offset, |
167 net::IOBuffer* buf, | 234 net::IOBuffer* buf, |
168 int buf_len, | 235 int buf_len, |
169 const CompletionCallback& callback, | 236 const CompletionCallback& callback, |
170 bool truncate) { | 237 bool truncate) { |
238 LOG(INFO) << " WRITE " << key_ << " buf " << buf << " buf_len " << buf_len << " truncate " << truncate; | |
171 DCHECK(io_thread_checker_.CalledOnValidThread()); | 239 DCHECK(io_thread_checker_.CalledOnValidThread()); |
240 | |
172 if (synchronous_entry_in_use_by_worker_) { | 241 if (synchronous_entry_in_use_by_worker_) { |
173 NOTIMPLEMENTED(); | 242 LOG(INFO) << " WRITE " << key_; |
174 CHECK(false); | 243 // Postpone write operation. |
244 operations_.push( | |
245 base::Bind(&SimpleEntryImpl::WriteDataInternal, | |
246 weak_ptr_factory_.GetWeakPtr(), | |
247 index, | |
248 offset, | |
249 make_scoped_refptr(buf), | |
250 buf_len, | |
251 callback, | |
252 truncate)); | |
253 // When writting, if there is already a pending operation, we have to return | |
254 // pending. | |
255 return net::ERR_IO_PENDING; | |
175 } | 256 } |
257 LOG(INFO) << " WRITE " << key_; | |
258 DCHECK(operations_.size() == 0); | |
259 WriteDataInternal(index, | |
260 offset, | |
261 make_scoped_refptr(buf), | |
262 buf_len, | |
263 //callback, | |
264 base::Bind(&WriteDataNoOp), | |
265 truncate); | |
266 //return net::ERR_IO_PENDING; | |
267 // Pretend everything goes fine, and make HTTP Cache Transaction happy. | |
268 return buf_len; | |
269 } | |
270 | |
271 void SimpleEntryImpl::WriteDataInternal(int index, | |
272 int offset, | |
273 scoped_refptr<net::IOBuffer> buf, | |
274 int buf_len, | |
275 const CompletionCallback& callback, | |
276 bool truncate) { | |
277 DCHECK(io_thread_checker_.CalledOnValidThread()); | |
278 DCHECK(!synchronous_entry_in_use_by_worker_); | |
279 read_only_operation_ = false; | |
176 synchronous_entry_in_use_by_worker_ = true; | 280 synchronous_entry_in_use_by_worker_ = true; |
177 if (index_) | 281 if (index_) |
178 index_->UseIfExists(key_); | 282 index_->UseIfExists(key_); |
283 | |
284 // TODO(felipeg): last_used_ last_modified_ | |
285 | |
286 data_size_[index] = buf_len; | |
287 | |
179 SynchronousOperationCallback sync_operation_callback = | 288 SynchronousOperationCallback sync_operation_callback = |
180 base::Bind(&SimpleEntryImpl::EntryOperationComplete, | 289 base::Bind(&SimpleEntryImpl::EntryOperationComplete, |
181 index_, callback, weak_ptr_factory_.GetWeakPtr(), | 290 index_, callback, weak_ptr_factory_.GetWeakPtr(), |
182 synchronous_entry_); | 291 synchronous_entry_); |
183 WorkerPool::PostTask(FROM_HERE, | 292 WorkerPool::PostTask(FROM_HERE, |
184 base::Bind(&SimpleSynchronousEntry::WriteData, | 293 base::Bind(&SimpleSynchronousEntry::WriteData, |
185 base::Unretained(synchronous_entry_), | 294 base::Unretained(synchronous_entry_), |
186 index, offset, make_scoped_refptr(buf), | 295 index, offset, buf, |
187 buf_len, sync_operation_callback, truncate), | 296 buf_len, sync_operation_callback, truncate), |
188 true); | 297 true); |
189 return net::ERR_IO_PENDING; | 298 LOG(INFO) << " WRITE " << key_; |
190 } | 299 } |
191 | 300 |
192 int SimpleEntryImpl::ReadSparseData(int64 offset, | 301 int SimpleEntryImpl::ReadSparseData(int64 offset, |
193 net::IOBuffer* buf, | 302 net::IOBuffer* buf, |
194 int buf_len, | 303 int buf_len, |
195 const CompletionCallback& callback) { | 304 const CompletionCallback& callback) { |
196 DCHECK(io_thread_checker_.CalledOnValidThread()); | 305 DCHECK(io_thread_checker_.CalledOnValidThread()); |
197 // TODO(gavinp): Determine if the simple backend should support sparse data. | 306 // TODO(gavinp): Determine if the simple backend should support sparse data. |
198 NOTIMPLEMENTED(); | 307 NOTIMPLEMENTED(); |
199 return net::ERR_FAILED; | 308 return net::ERR_FAILED; |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
239 } | 348 } |
240 | 349 |
241 SimpleEntryImpl::SimpleEntryImpl( | 350 SimpleEntryImpl::SimpleEntryImpl( |
242 SimpleSynchronousEntry* synchronous_entry, | 351 SimpleSynchronousEntry* synchronous_entry, |
243 WeakPtr<SimpleIndex> index) | 352 WeakPtr<SimpleIndex> index) |
244 : ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)), | 353 : ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)), |
245 path_(synchronous_entry->path()), | 354 path_(synchronous_entry->path()), |
246 key_(synchronous_entry->key()), | 355 key_(synchronous_entry->key()), |
247 synchronous_entry_(synchronous_entry), | 356 synchronous_entry_(synchronous_entry), |
248 synchronous_entry_in_use_by_worker_(false), | 357 synchronous_entry_in_use_by_worker_(false), |
358 read_only_operation_(false), | |
249 index_(index) { | 359 index_(index) { |
250 DCHECK(synchronous_entry); | 360 DCHECK(synchronous_entry); |
251 SetSynchronousData(); | 361 SetSynchronousData(); |
252 } | 362 } |
253 | 363 |
254 SimpleEntryImpl::~SimpleEntryImpl() { | 364 SimpleEntryImpl::~SimpleEntryImpl() { |
255 DCHECK(io_thread_checker_.CalledOnValidThread()); | 365 DCHECK(io_thread_checker_.CalledOnValidThread()); |
256 } | 366 } |
257 | 367 |
258 // static | 368 // static |
(...skipping 25 matching lines...) Expand all Loading... | |
284 int result) { | 394 int result) { |
285 DCHECK(sync_entry); | 395 DCHECK(sync_entry); |
286 if (index) { | 396 if (index) { |
287 if (result >= 0) | 397 if (result >= 0) |
288 index->UpdateEntrySize(sync_entry->key(), sync_entry->GetFileSize()); | 398 index->UpdateEntrySize(sync_entry->key(), sync_entry->GetFileSize()); |
289 else | 399 else |
290 index->Remove(sync_entry->key()); | 400 index->Remove(sync_entry->key()); |
291 } | 401 } |
292 | 402 |
293 if (entry) { | 403 if (entry) { |
404 if (entry->read_only_operation_) | |
405 LOG(INFO) << " READ EntryOperationComplete " << entry->key(); | |
406 else | |
407 LOG(INFO) << " WRITE EntryOperationComplete " << entry->key(); | |
294 DCHECK(entry->synchronous_entry_in_use_by_worker_); | 408 DCHECK(entry->synchronous_entry_in_use_by_worker_); |
409 entry->read_only_operation_ = false; | |
295 entry->synchronous_entry_in_use_by_worker_ = false; | 410 entry->synchronous_entry_in_use_by_worker_ = false; |
296 entry->SetSynchronousData(); | 411 entry->SetSynchronousData(); |
412 | |
413 entry->RunNextOperationIfNeeded(); | |
414 | |
415 completion_callback.Run(result); | |
297 } else { | 416 } else { |
417 | |
418 LOG(INFO) << " EntryOperationComplete " << entry->key(); | |
298 // |entry| must have had Close() called while this operation was in flight. | 419 // |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 | 420 // 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|. | 421 // flight at a time, it's safe to now call Close() on |sync_entry|. |
301 WorkerPool::PostTask(FROM_HERE, | 422 WorkerPool::PostTask(FROM_HERE, |
302 base::Bind(&SimpleSynchronousEntry::Close, | 423 base::Bind(&SimpleSynchronousEntry::Close, |
303 base::Unretained(sync_entry)), | 424 base::Unretained(sync_entry)), |
304 true); | 425 true); |
426 | |
427 completion_callback.Run(result); | |
305 } | 428 } |
306 completion_callback.Run(result); | 429 } |
430 | |
431 void SimpleEntryImpl::RunNextOperationIfNeeded() { | |
432 LOG(INFO) << " RunNextOperationIfNeeded " << key_; | |
433 DCHECK(io_thread_checker_.CalledOnValidThread()); | |
434 if (operations_.size() <= 0) | |
435 return; | |
436 base::Closure operation = operations_.front(); | |
437 operations_.pop(); | |
438 | |
439 LOG(INFO) << " operation.Run " << key_; | |
440 // TODO(felipeg): maybe we should post task. But it could shuffle even more | |
441 // the order of new operations in this entry. | |
gavinp
2013/04/17 08:17:14
The callers should be totally insensitive to the o
felipeg
2013/04/17 10:06:43
No post is better because when debugging our minds
| |
442 operation.Run(); | |
307 } | 443 } |
308 | 444 |
309 void SimpleEntryImpl::SetSynchronousData() { | 445 void SimpleEntryImpl::SetSynchronousData() { |
310 DCHECK(io_thread_checker_.CalledOnValidThread()); | 446 DCHECK(io_thread_checker_.CalledOnValidThread()); |
311 DCHECK(!synchronous_entry_in_use_by_worker_); | 447 DCHECK(!synchronous_entry_in_use_by_worker_); |
312 // TODO(felipeg): These copies to avoid data races are not optimal. While | 448 // 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 | 449 // 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 | 450 // in that structure. This also solves problems with last_used() on ext4 |
315 // filesystems not being accurate. | 451 // filesystems not being accurate. |
316 last_used_ = synchronous_entry_->last_used(); | 452 last_used_ = synchronous_entry_->last_used(); |
317 last_modified_ = synchronous_entry_->last_modified(); | 453 last_modified_ = synchronous_entry_->last_modified(); |
318 for (int i = 0; i < kSimpleEntryFileCount; ++i) | 454 for (int i = 0; i < kSimpleEntryFileCount; ++i) |
319 data_size_[i] = synchronous_entry_->data_size(i); | 455 data_size_[i] = synchronous_entry_->data_size(i); |
320 } | 456 } |
321 | 457 |
322 } // namespace disk_cache | 458 } // namespace disk_cache |
OLD | NEW |