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

Side by Side Diff: net/disk_cache/simple/simple_entry_impl.cc

Issue 14130015: Support overlapping operations on the SimpleEntryImpl. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 8 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
« no previous file with comments | « net/disk_cache/simple/simple_entry_impl.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
OLDNEW
« no previous file with comments | « net/disk_cache/simple/simple_entry_impl.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698