| 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 <algorithm> | 7 #include <algorithm> |
| 8 #include <cstring> | 8 #include <cstring> |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 72 open_count_(0), | 72 open_count_(0), |
| 73 state_(STATE_UNINITIALIZED), | 73 state_(STATE_UNINITIALIZED), |
| 74 synchronous_entry_(NULL) { | 74 synchronous_entry_(NULL) { |
| 75 DCHECK_EQ(entry_hash, simple_util::GetEntryHashKey(key)); | 75 DCHECK_EQ(entry_hash, simple_util::GetEntryHashKey(key)); |
| 76 COMPILE_ASSERT(arraysize(data_size_) == arraysize(crc32s_end_offset_), | 76 COMPILE_ASSERT(arraysize(data_size_) == arraysize(crc32s_end_offset_), |
| 77 arrays_should_be_same_size); | 77 arrays_should_be_same_size); |
| 78 COMPILE_ASSERT(arraysize(data_size_) == arraysize(crc32s_), | 78 COMPILE_ASSERT(arraysize(data_size_) == arraysize(crc32s_), |
| 79 arrays_should_be_same_size2); | 79 arrays_should_be_same_size2); |
| 80 COMPILE_ASSERT(arraysize(data_size_) == arraysize(have_written_), | 80 COMPILE_ASSERT(arraysize(data_size_) == arraysize(have_written_), |
| 81 arrays_should_be_same_size3); | 81 arrays_should_be_same_size3); |
| 82 | |
| 83 MakeUninitialized(); | 82 MakeUninitialized(); |
| 84 } | 83 } |
| 85 | 84 |
| 86 int SimpleEntryImpl::OpenEntry(Entry** out_entry, | 85 int SimpleEntryImpl::OpenEntry(Entry** out_entry, |
| 87 const CompletionCallback& callback) { | 86 const CompletionCallback& callback) { |
| 88 DCHECK(backend_); | 87 DCHECK(backend_); |
| 88 // This enumeration is used in histograms, add entries only at end. |
| 89 enum OpenEntryIndexEnum { |
| 90 INDEX_NOEXIST = 0, |
| 91 INDEX_MISS = 1, |
| 92 INDEX_HIT = 2, |
| 93 INDEX_MAX = 3, |
| 94 }; |
| 95 OpenEntryIndexEnum open_entry_index_enum = INDEX_NOEXIST; |
| 96 if (backend_) { |
| 97 if (backend_->index()->Has(key_)) |
| 98 open_entry_index_enum = INDEX_HIT; |
| 99 else |
| 100 open_entry_index_enum = INDEX_MISS; |
| 101 } |
| 102 UMA_HISTOGRAM_ENUMERATION("SimpleCache.OpenEntryIndexState", |
| 103 open_entry_index_enum, INDEX_MAX); |
| 104 |
| 105 // If entry is not known to the index, initiate fast failover to the network. |
| 106 if (open_entry_index_enum == INDEX_MISS) |
| 107 return net::ERR_FAILED; |
| 89 | 108 |
| 90 pending_operations_.push(base::Bind(&SimpleEntryImpl::OpenEntryInternal, | 109 pending_operations_.push(base::Bind(&SimpleEntryImpl::OpenEntryInternal, |
| 91 this, out_entry, callback)); | 110 this, callback, out_entry)); |
| 92 RunNextOperationIfNeeded(); | 111 RunNextOperationIfNeeded(); |
| 93 return net::ERR_IO_PENDING; | 112 return net::ERR_IO_PENDING; |
| 94 } | 113 } |
| 95 | 114 |
| 96 int SimpleEntryImpl::CreateEntry(Entry** out_entry, | 115 int SimpleEntryImpl::CreateEntry(Entry** out_entry, |
| 97 const CompletionCallback& callback) { | 116 const CompletionCallback& callback) { |
| 98 DCHECK(backend_); | 117 DCHECK(backend_); |
| 99 pending_operations_.push(base::Bind(&SimpleEntryImpl::CreateEntryInternal, | 118 int ret_value = net::ERR_FAILED; |
| 100 this, out_entry, callback)); | 119 if (state_ == STATE_UNINITIALIZED && |
| 120 pending_operations_.size() == 0) { |
| 121 ReturnEntryToCaller(out_entry); |
| 122 // We can do optimistic Create. |
| 123 pending_operations_.push(base::Bind(&SimpleEntryImpl::CreateEntryInternal, |
| 124 this, |
| 125 CompletionCallback(), |
| 126 static_cast<Entry**>(NULL))); |
| 127 ret_value = net::OK; |
| 128 } else { |
| 129 pending_operations_.push(base::Bind(&SimpleEntryImpl::CreateEntryInternal, |
| 130 this, |
| 131 callback, |
| 132 out_entry)); |
| 133 ret_value = net::ERR_IO_PENDING; |
| 134 } |
| 135 |
| 136 // We insert the entry in the index before creating the entry files in the |
| 137 // SimpleSynchronousEntry, because this way the worst scenario is when we |
| 138 // have the entry in the index but we don't have the created files yet, this |
| 139 // way we never leak files. CreationOperationComplete will remove the entry |
| 140 // from the index if the creation fails. |
| 141 if (backend_) |
| 142 backend_->index()->Insert(key_); |
| 143 |
| 144 // Since we don't know the correct values for |last_used_| and |
| 145 // |last_modified_| yet, we make this approximation. |
| 146 last_used_ = last_modified_ = base::Time::Now(); |
| 147 |
| 101 RunNextOperationIfNeeded(); | 148 RunNextOperationIfNeeded(); |
| 102 return net::ERR_IO_PENDING; | 149 return ret_value; |
| 103 } | 150 } |
| 104 | 151 |
| 105 int SimpleEntryImpl::DoomEntry(const CompletionCallback& callback) { | 152 int SimpleEntryImpl::DoomEntry(const CompletionCallback& callback) { |
| 106 MarkAsDoomed(); | 153 MarkAsDoomed(); |
| 107 | |
| 108 scoped_ptr<int> result(new int()); | 154 scoped_ptr<int> result(new int()); |
| 109 Closure task = base::Bind(&SimpleSynchronousEntry::DoomEntry, path_, key_, | 155 Closure task = base::Bind(&SimpleSynchronousEntry::DoomEntry, path_, key_, |
| 110 entry_hash_, result.get()); | 156 entry_hash_, result.get()); |
| 111 Closure reply = base::Bind(&CallCompletionCallback, | 157 Closure reply = base::Bind(&CallCompletionCallback, |
| 112 callback, base::Passed(&result)); | 158 callback, base::Passed(&result)); |
| 113 WorkerPool::PostTaskAndReply(FROM_HERE, task, reply, true); | 159 WorkerPool::PostTaskAndReply(FROM_HERE, task, reply, true); |
| 114 return net::ERR_IO_PENDING; | 160 return net::ERR_IO_PENDING; |
| 115 } | 161 } |
| 116 | 162 |
| 117 | 163 |
| (...skipping 27 matching lines...) Expand all Loading... |
| 145 return last_used_; | 191 return last_used_; |
| 146 } | 192 } |
| 147 | 193 |
| 148 Time SimpleEntryImpl::GetLastModified() const { | 194 Time SimpleEntryImpl::GetLastModified() const { |
| 149 DCHECK(io_thread_checker_.CalledOnValidThread()); | 195 DCHECK(io_thread_checker_.CalledOnValidThread()); |
| 150 return last_modified_; | 196 return last_modified_; |
| 151 } | 197 } |
| 152 | 198 |
| 153 int32 SimpleEntryImpl::GetDataSize(int stream_index) const { | 199 int32 SimpleEntryImpl::GetDataSize(int stream_index) const { |
| 154 DCHECK(io_thread_checker_.CalledOnValidThread()); | 200 DCHECK(io_thread_checker_.CalledOnValidThread()); |
| 201 DCHECK_LE(0, data_size_[stream_index]); |
| 155 return data_size_[stream_index]; | 202 return data_size_[stream_index]; |
| 156 } | 203 } |
| 157 | 204 |
| 158 int SimpleEntryImpl::ReadData(int stream_index, | 205 int SimpleEntryImpl::ReadData(int stream_index, |
| 159 int offset, | 206 int offset, |
| 160 net::IOBuffer* buf, | 207 net::IOBuffer* buf, |
| 161 int buf_len, | 208 int buf_len, |
| 162 const CompletionCallback& callback) { | 209 const CompletionCallback& callback) { |
| 163 DCHECK(io_thread_checker_.CalledOnValidThread()); | 210 DCHECK(io_thread_checker_.CalledOnValidThread()); |
| 164 if (stream_index < 0 || stream_index >= kSimpleEntryFileCount || buf_len < 0) | 211 if (stream_index < 0 || stream_index >= kSimpleEntryFileCount || buf_len < 0) |
| 165 return net::ERR_INVALID_ARGUMENT; | 212 return net::ERR_INVALID_ARGUMENT; |
| 166 if (offset >= data_size_[stream_index] || offset < 0 || !buf_len) | 213 if (offset >= data_size_[stream_index] || offset < 0 || !buf_len) |
| 167 return 0; | 214 return 0; |
| 168 buf_len = std::min(buf_len, data_size_[stream_index] - offset); | 215 |
| 169 // TODO(felipeg): Optimization: Add support for truly parallel read | 216 // TODO(felipeg): Optimization: Add support for truly parallel read |
| 170 // operations. | 217 // operations. |
| 171 pending_operations_.push( | 218 pending_operations_.push( |
| 172 base::Bind(&SimpleEntryImpl::ReadDataInternal, | 219 base::Bind(&SimpleEntryImpl::ReadDataInternal, |
| 173 this, | 220 this, |
| 174 stream_index, | 221 stream_index, |
| 175 offset, | 222 offset, |
| 176 make_scoped_refptr(buf), | 223 make_scoped_refptr(buf), |
| 177 buf_len, | 224 buf_len, |
| 178 callback)); | 225 callback)); |
| 179 RunNextOperationIfNeeded(); | 226 RunNextOperationIfNeeded(); |
| 180 return net::ERR_IO_PENDING; | 227 return net::ERR_IO_PENDING; |
| 181 } | 228 } |
| 182 | 229 |
| 183 int SimpleEntryImpl::WriteData(int stream_index, | 230 int SimpleEntryImpl::WriteData(int stream_index, |
| 184 int offset, | 231 int offset, |
| 185 net::IOBuffer* buf, | 232 net::IOBuffer* buf, |
| 186 int buf_len, | 233 int buf_len, |
| 187 const CompletionCallback& callback, | 234 const CompletionCallback& callback, |
| 188 bool truncate) { | 235 bool truncate) { |
| 189 DCHECK(io_thread_checker_.CalledOnValidThread()); | 236 DCHECK(io_thread_checker_.CalledOnValidThread()); |
| 190 if (stream_index < 0 || stream_index >= kSimpleEntryFileCount || offset < 0 || | 237 if (stream_index < 0 || stream_index >= kSimpleEntryFileCount || offset < 0 || |
| 191 buf_len < 0) { | 238 buf_len < 0) { |
| 192 return net::ERR_INVALID_ARGUMENT; | 239 return net::ERR_INVALID_ARGUMENT; |
| 193 } | 240 } |
| 194 pending_operations_.push( | 241 |
| 195 base::Bind(&SimpleEntryImpl::WriteDataInternal, | 242 int ret_value = net::ERR_FAILED; |
| 196 this, | 243 if (state_ == STATE_READY && pending_operations_.size() == 0) { |
| 197 stream_index, | 244 // We can only do optimistic Write if there is no pending operations, so |
| 198 offset, | 245 // that we are sure that the next call to RunNextOperationIfNeeded will |
| 199 make_scoped_refptr(buf), | 246 // actually run the write operation that sets the stream size. It also |
| 200 buf_len, | 247 // prevents from previous possibly-conflicting writes that could be stacked |
| 201 callback, | 248 // in the |pending_operations_|. We could optimize this for when we have |
| 202 truncate)); | 249 // only read operations enqueued. |
| 250 pending_operations_.push( |
| 251 base::Bind(&SimpleEntryImpl::WriteDataInternal, this, stream_index, |
| 252 offset, make_scoped_refptr(buf), buf_len, |
| 253 CompletionCallback(), truncate)); |
| 254 ret_value = buf_len; |
| 255 } else { |
| 256 pending_operations_.push( |
| 257 base::Bind(&SimpleEntryImpl::WriteDataInternal, this, stream_index, |
| 258 offset, make_scoped_refptr(buf), buf_len, callback, |
| 259 truncate)); |
| 260 ret_value = net::ERR_IO_PENDING; |
| 261 } |
| 262 |
| 263 if (truncate) |
| 264 data_size_[stream_index] = offset + buf_len; |
| 265 else |
| 266 data_size_[stream_index] = std::max(offset + buf_len, |
| 267 data_size_[stream_index]); |
| 268 |
| 269 // Since we don't know the correct values for |last_used_| and |
| 270 // |last_modified_| yet, we make this approximation. |
| 271 last_used_ = last_modified_ = base::Time::Now(); |
| 272 |
| 203 RunNextOperationIfNeeded(); | 273 RunNextOperationIfNeeded(); |
| 204 // TODO(felipeg): Optimization: Add support for optimistic writes, quickly | 274 return ret_value; |
| 205 // returning net::OK here. | |
| 206 return net::ERR_IO_PENDING; | |
| 207 } | 275 } |
| 208 | 276 |
| 209 int SimpleEntryImpl::ReadSparseData(int64 offset, | 277 int SimpleEntryImpl::ReadSparseData(int64 offset, |
| 210 net::IOBuffer* buf, | 278 net::IOBuffer* buf, |
| 211 int buf_len, | 279 int buf_len, |
| 212 const CompletionCallback& callback) { | 280 const CompletionCallback& callback) { |
| 213 DCHECK(io_thread_checker_.CalledOnValidThread()); | 281 DCHECK(io_thread_checker_.CalledOnValidThread()); |
| 214 // TODO(gavinp): Determine if the simple backend should support sparse data. | 282 // TODO(gavinp): Determine if the simple backend should support sparse data. |
| 215 NOTIMPLEMENTED(); | 283 NOTIMPLEMENTED(); |
| 216 return net::ERR_FAILED; | 284 return net::ERR_FAILED; |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 251 int SimpleEntryImpl::ReadyForSparseIO(const CompletionCallback& callback) { | 319 int SimpleEntryImpl::ReadyForSparseIO(const CompletionCallback& callback) { |
| 252 DCHECK(io_thread_checker_.CalledOnValidThread()); | 320 DCHECK(io_thread_checker_.CalledOnValidThread()); |
| 253 // TODO(gavinp): Determine if the simple backend should support sparse data. | 321 // TODO(gavinp): Determine if the simple backend should support sparse data. |
| 254 NOTIMPLEMENTED(); | 322 NOTIMPLEMENTED(); |
| 255 return net::ERR_FAILED; | 323 return net::ERR_FAILED; |
| 256 } | 324 } |
| 257 | 325 |
| 258 SimpleEntryImpl::~SimpleEntryImpl() { | 326 SimpleEntryImpl::~SimpleEntryImpl() { |
| 259 DCHECK(io_thread_checker_.CalledOnValidThread()); | 327 DCHECK(io_thread_checker_.CalledOnValidThread()); |
| 260 DCHECK_EQ(0U, pending_operations_.size()); | 328 DCHECK_EQ(0U, pending_operations_.size()); |
| 261 DCHECK_EQ(STATE_UNINITIALIZED, state_); | 329 DCHECK(STATE_UNINITIALIZED == state_ || STATE_FAILURE == state_); |
| 262 DCHECK(!synchronous_entry_); | 330 DCHECK(!synchronous_entry_); |
| 263 RemoveSelfFromBackend(); | 331 RemoveSelfFromBackend(); |
| 264 } | 332 } |
| 265 | 333 |
| 266 void SimpleEntryImpl::MakeUninitialized() { | 334 void SimpleEntryImpl::MakeUninitialized() { |
| 267 state_ = STATE_UNINITIALIZED; | 335 state_ = STATE_UNINITIALIZED; |
| 268 std::memset(crc32s_end_offset_, 0, sizeof(crc32s_end_offset_)); | 336 std::memset(crc32s_end_offset_, 0, sizeof(crc32s_end_offset_)); |
| 269 std::memset(crc32s_, 0, sizeof(crc32s_)); | 337 std::memset(crc32s_, 0, sizeof(crc32s_)); |
| 270 std::memset(have_written_, 0, sizeof(have_written_)); | 338 std::memset(have_written_, 0, sizeof(have_written_)); |
| 339 std::memset(data_size_, 0, sizeof(data_size_)); |
| 271 } | 340 } |
| 272 | 341 |
| 273 void SimpleEntryImpl::ReturnEntryToCaller(Entry** out_entry) { | 342 void SimpleEntryImpl::ReturnEntryToCaller(Entry** out_entry) { |
| 343 DCHECK(out_entry); |
| 274 ++open_count_; | 344 ++open_count_; |
| 275 AddRef(); // Balanced in Close() | 345 AddRef(); // Balanced in Close() |
| 276 *out_entry = this; | 346 *out_entry = this; |
| 277 } | 347 } |
| 278 | 348 |
| 279 void SimpleEntryImpl::RemoveSelfFromBackend() { | 349 void SimpleEntryImpl::RemoveSelfFromBackend() { |
| 280 if (!backend_) | 350 if (!backend_) |
| 281 return; | 351 return; |
| 282 backend_->OnDeactivated(this); | 352 backend_->OnDeactivated(this); |
| 283 backend_.reset(); | 353 backend_.reset(); |
| 284 } | 354 } |
| 285 | 355 |
| 286 void SimpleEntryImpl::MarkAsDoomed() { | 356 void SimpleEntryImpl::MarkAsDoomed() { |
| 287 if (!backend_) | 357 if (!backend_) |
| 288 return; | 358 return; |
| 289 backend_->index()->Remove(key_); | 359 backend_->index()->Remove(key_); |
| 290 RemoveSelfFromBackend(); | 360 RemoveSelfFromBackend(); |
| 291 } | 361 } |
| 292 | 362 |
| 293 void SimpleEntryImpl::RunNextOperationIfNeeded() { | 363 void SimpleEntryImpl::RunNextOperationIfNeeded() { |
| 294 DCHECK(io_thread_checker_.CalledOnValidThread()); | 364 DCHECK(io_thread_checker_.CalledOnValidThread()); |
| 295 | |
| 296 UMA_HISTOGRAM_CUSTOM_COUNTS("SimpleCache.EntryOperationsPending", | 365 UMA_HISTOGRAM_CUSTOM_COUNTS("SimpleCache.EntryOperationsPending", |
| 297 pending_operations_.size(), 0, 100, 20); | 366 pending_operations_.size(), 0, 100, 20); |
| 298 | |
| 299 if (!pending_operations_.empty() && state_ != STATE_IO_PENDING) { | 367 if (!pending_operations_.empty() && state_ != STATE_IO_PENDING) { |
| 300 base::Closure operation = pending_operations_.front(); | 368 base::Closure operation = pending_operations_.front(); |
| 301 pending_operations_.pop(); | 369 pending_operations_.pop(); |
| 302 operation.Run(); | 370 operation.Run(); |
| 303 // |this| may have been deleted. | 371 // |this| may have been deleted. |
| 304 } | 372 } |
| 305 } | 373 } |
| 306 | 374 |
| 307 void SimpleEntryImpl::OpenEntryInternal(Entry** out_entry, | 375 void SimpleEntryImpl::OpenEntryInternal(const CompletionCallback& callback, |
| 308 const CompletionCallback& callback) { | 376 Entry** out_entry) { |
| 309 ScopedOperationRunner operation_runner(this); | 377 ScopedOperationRunner operation_runner(this); |
| 310 | |
| 311 if (state_ == STATE_READY) { | 378 if (state_ == STATE_READY) { |
| 312 ReturnEntryToCaller(out_entry); | 379 ReturnEntryToCaller(out_entry); |
| 313 MessageLoopProxy::current()->PostTask(FROM_HERE, base::Bind(callback, | 380 if (!callback.is_null()) { |
| 314 net::OK)); | 381 MessageLoopProxy::current()->PostTask(FROM_HERE, base::Bind(callback, |
| 382 net::OK)); |
| 383 } |
| 384 return; |
| 385 } else if (state_ == STATE_FAILURE) { |
| 386 if (!callback.is_null()) { |
| 387 MessageLoopProxy::current()->PostTask(FROM_HERE, base::Bind( |
| 388 callback, net::ERR_FAILED)); |
| 389 } |
| 315 return; | 390 return; |
| 316 } | 391 } |
| 317 DCHECK_EQ(STATE_UNINITIALIZED, state_); | 392 DCHECK_EQ(STATE_UNINITIALIZED, state_); |
| 318 | |
| 319 // This enumeration is used in histograms, add entries only at end. | |
| 320 enum OpenEntryIndexEnum { | |
| 321 INDEX_NOEXIST = 0, | |
| 322 INDEX_MISS = 1, | |
| 323 INDEX_HIT = 2, | |
| 324 INDEX_MAX = 3, | |
| 325 }; | |
| 326 OpenEntryIndexEnum open_entry_index_enum = INDEX_NOEXIST; | |
| 327 if (backend_) { | |
| 328 if (backend_->index()->Has(key_)) | |
| 329 open_entry_index_enum = INDEX_HIT; | |
| 330 else | |
| 331 open_entry_index_enum = INDEX_MISS; | |
| 332 } | |
| 333 UMA_HISTOGRAM_ENUMERATION("SimpleCache.OpenEntryIndexState", | |
| 334 open_entry_index_enum, INDEX_MAX); | |
| 335 // If entry is not known to the index, initiate fast failover to the network. | |
| 336 if (open_entry_index_enum == INDEX_MISS) { | |
| 337 MessageLoopProxy::current()->PostTask(FROM_HERE, | |
| 338 base::Bind(callback, | |
| 339 net::ERR_FAILED)); | |
| 340 return; | |
| 341 } | |
| 342 state_ = STATE_IO_PENDING; | 393 state_ = STATE_IO_PENDING; |
| 343 | |
| 344 const base::TimeTicks start_time = base::TimeTicks::Now(); | 394 const base::TimeTicks start_time = base::TimeTicks::Now(); |
| 345 typedef SimpleSynchronousEntry* PointerToSimpleSynchronousEntry; | 395 typedef SimpleSynchronousEntry* PointerToSimpleSynchronousEntry; |
| 346 scoped_ptr<PointerToSimpleSynchronousEntry> sync_entry( | 396 scoped_ptr<PointerToSimpleSynchronousEntry> sync_entry( |
| 347 new PointerToSimpleSynchronousEntry()); | 397 new PointerToSimpleSynchronousEntry()); |
| 348 scoped_ptr<int> result(new int()); | 398 scoped_ptr<int> result(new int()); |
| 349 Closure task = base::Bind(&SimpleSynchronousEntry::OpenEntry, path_, key_, | 399 Closure task = base::Bind(&SimpleSynchronousEntry::OpenEntry, path_, key_, |
| 350 entry_hash_, sync_entry.get(), result.get()); | 400 entry_hash_, sync_entry.get(), result.get()); |
| 351 Closure reply = base::Bind(&SimpleEntryImpl::CreationOperationComplete, this, | 401 Closure reply = base::Bind(&SimpleEntryImpl::CreationOperationComplete, this, |
| 352 callback, start_time, base::Passed(&sync_entry), | 402 callback, start_time, base::Passed(&sync_entry), |
| 353 base::Passed(&result), out_entry); | 403 base::Passed(&result), out_entry); |
| 354 WorkerPool::PostTaskAndReply(FROM_HERE, task, reply, true); | 404 WorkerPool::PostTaskAndReply(FROM_HERE, task, reply, true); |
| 355 } | 405 } |
| 356 | 406 |
| 357 void SimpleEntryImpl::CreateEntryInternal(Entry** out_entry, | 407 void SimpleEntryImpl::CreateEntryInternal(const CompletionCallback& callback, |
| 358 const CompletionCallback& callback) { | 408 Entry** out_entry) { |
| 359 ScopedOperationRunner operation_runner(this); | 409 ScopedOperationRunner operation_runner(this); |
| 360 | 410 if (state_ != STATE_UNINITIALIZED) { |
| 361 if (state_ == STATE_READY) { | |
| 362 // There is already an active normal entry. | 411 // There is already an active normal entry. |
| 363 MessageLoopProxy::current()->PostTask(FROM_HERE, | 412 if (!callback.is_null()) { |
| 364 base::Bind(callback, | 413 MessageLoopProxy::current()->PostTask(FROM_HERE, base::Bind( |
| 365 net::ERR_FAILED)); | 414 callback, net::ERR_FAILED)); |
| 415 } |
| 366 return; | 416 return; |
| 367 } | 417 } |
| 368 DCHECK_EQ(STATE_UNINITIALIZED, state_); | 418 DCHECK_EQ(STATE_UNINITIALIZED, state_); |
| 369 | 419 |
| 370 state_ = STATE_IO_PENDING; | 420 state_ = STATE_IO_PENDING; |
| 371 | 421 |
| 372 // If creation succeeds, we should mark all streams to be saved on close. | 422 // If creation succeeds, we should mark all streams to be saved on close. |
| 373 for (int i = 0; i < kSimpleEntryFileCount; ++i) | 423 for (int i = 0; i < kSimpleEntryFileCount; ++i) |
| 374 have_written_[i] = true; | 424 have_written_[i] = true; |
| 375 | 425 |
| 376 // We insert the entry in the index before creating the entry files in the | |
| 377 // SimpleSynchronousEntry, because this way the worst scenario is when we | |
| 378 // have the entry in the index but we don't have the created files yet, this | |
| 379 // way we never leak files. CreationOperationComplete will remove the entry | |
| 380 // from the index if the creation fails. | |
| 381 if (backend_) | |
| 382 backend_->index()->Insert(key_); | |
| 383 const base::TimeTicks start_time = base::TimeTicks::Now(); | 426 const base::TimeTicks start_time = base::TimeTicks::Now(); |
| 384 typedef SimpleSynchronousEntry* PointerToSimpleSynchronousEntry; | 427 typedef SimpleSynchronousEntry* PointerToSimpleSynchronousEntry; |
| 385 scoped_ptr<PointerToSimpleSynchronousEntry> sync_entry( | 428 scoped_ptr<PointerToSimpleSynchronousEntry> sync_entry( |
| 386 new PointerToSimpleSynchronousEntry()); | 429 new PointerToSimpleSynchronousEntry()); |
| 387 scoped_ptr<int> result(new int()); | 430 scoped_ptr<int> result(new int()); |
| 388 Closure task = base::Bind(&SimpleSynchronousEntry::CreateEntry, path_, key_, | 431 Closure task = base::Bind(&SimpleSynchronousEntry::CreateEntry, path_, key_, |
| 389 entry_hash_, sync_entry.get(), result.get()); | 432 entry_hash_, sync_entry.get(), result.get()); |
| 390 Closure reply = base::Bind(&SimpleEntryImpl::CreationOperationComplete, this, | 433 Closure reply = base::Bind(&SimpleEntryImpl::CreationOperationComplete, this, |
| 391 callback, start_time, base::Passed(&sync_entry), | 434 callback, start_time, base::Passed(&sync_entry), |
| 392 base::Passed(&result), out_entry); | 435 base::Passed(&result), out_entry); |
| 393 WorkerPool::PostTaskAndReply(FROM_HERE, task, reply, true); | 436 WorkerPool::PostTaskAndReply(FROM_HERE, task, reply, true); |
| 394 } | 437 } |
| 395 | 438 |
| 396 void SimpleEntryImpl::CloseInternal() { | 439 void SimpleEntryImpl::CloseInternal() { |
| 397 DCHECK(io_thread_checker_.CalledOnValidThread()); | 440 DCHECK(io_thread_checker_.CalledOnValidThread()); |
| 398 DCHECK_EQ(0U, pending_operations_.size()); | |
| 399 DCHECK_EQ(STATE_READY, state_); | |
| 400 DCHECK(synchronous_entry_); | |
| 401 | |
| 402 state_ = STATE_IO_PENDING; | |
| 403 | |
| 404 typedef SimpleSynchronousEntry::CRCRecord CRCRecord; | 441 typedef SimpleSynchronousEntry::CRCRecord CRCRecord; |
| 405 | |
| 406 scoped_ptr<std::vector<CRCRecord> > | 442 scoped_ptr<std::vector<CRCRecord> > |
| 407 crc32s_to_write(new std::vector<CRCRecord>()); | 443 crc32s_to_write(new std::vector<CRCRecord>()); |
| 408 for (int i = 0; i < kSimpleEntryFileCount; ++i) { | 444 |
| 409 if (have_written_[i]) { | 445 if (state_ == STATE_READY) { |
| 410 if (data_size_[i] == crc32s_end_offset_[i]) { | 446 DCHECK(synchronous_entry_); |
| 411 int32 crc = data_size_[i] == 0 ? crc32(0, Z_NULL, 0) : crc32s_[i]; | 447 state_ = STATE_IO_PENDING; |
| 412 crc32s_to_write->push_back(CRCRecord(i, true, crc)); | 448 for (int i = 0; i < kSimpleEntryFileCount; ++i) { |
| 413 } else { | 449 if (have_written_[i]) { |
| 414 crc32s_to_write->push_back(CRCRecord(i, false, 0)); | 450 if (data_size_[i] == crc32s_end_offset_[i]) { |
| 451 int32 crc = data_size_[i] == 0 ? crc32(0, Z_NULL, 0) : crc32s_[i]; |
| 452 crc32s_to_write->push_back(CRCRecord(i, true, crc)); |
| 453 } else { |
| 454 crc32s_to_write->push_back(CRCRecord(i, false, 0)); |
| 455 } |
| 415 } | 456 } |
| 416 } | 457 } |
| 458 } else { |
| 459 DCHECK_EQ(STATE_FAILURE, state_); |
| 417 } | 460 } |
| 418 Closure task = base::Bind(&SimpleSynchronousEntry::Close, | 461 |
| 419 base::Unretained(synchronous_entry_), | 462 if (synchronous_entry_) { |
| 420 base::Passed(&crc32s_to_write)); | 463 Closure task = base::Bind(&SimpleSynchronousEntry::Close, |
| 421 Closure reply = base::Bind(&SimpleEntryImpl::CloseOperationComplete, this); | 464 base::Unretained(synchronous_entry_), |
| 422 WorkerPool::PostTaskAndReply(FROM_HERE, task, reply, true); | 465 base::Passed(&crc32s_to_write)); |
| 423 synchronous_entry_ = NULL; | 466 Closure reply = base::Bind(&SimpleEntryImpl::CloseOperationComplete, this); |
| 467 synchronous_entry_ = NULL; |
| 468 WorkerPool::PostTaskAndReply(FROM_HERE, task, reply, true); |
| 469 } else { |
| 470 synchronous_entry_ = NULL; |
| 471 CloseOperationComplete(); |
| 472 } |
| 424 } | 473 } |
| 425 | 474 |
| 426 void SimpleEntryImpl::ReadDataInternal(int stream_index, | 475 void SimpleEntryImpl::ReadDataInternal(int stream_index, |
| 427 int offset, | 476 int offset, |
| 428 net::IOBuffer* buf, | 477 net::IOBuffer* buf, |
| 429 int buf_len, | 478 int buf_len, |
| 430 const CompletionCallback& callback) { | 479 const CompletionCallback& callback) { |
| 431 DCHECK(io_thread_checker_.CalledOnValidThread()); | 480 DCHECK(io_thread_checker_.CalledOnValidThread()); |
| 481 ScopedOperationRunner operation_runner(this); |
| 482 |
| 483 if (state_ == STATE_FAILURE || state_ == STATE_UNINITIALIZED) { |
| 484 if (!callback.is_null()) { |
| 485 MessageLoopProxy::current()->PostTask(FROM_HERE, base::Bind( |
| 486 callback, net::ERR_FAILED)); |
| 487 } |
| 488 return; |
| 489 } |
| 432 DCHECK_EQ(STATE_READY, state_); | 490 DCHECK_EQ(STATE_READY, state_); |
| 491 buf_len = std::min(buf_len, GetDataSize(stream_index) - offset); |
| 492 if (offset < 0 || buf_len <= 0) { |
| 493 // If there is nothing to read, we bail out before setting state_ to |
| 494 // STATE_IO_PENDING. |
| 495 if (!callback.is_null()) |
| 496 MessageLoopProxy::current()->PostTask(FROM_HERE, base::Bind( |
| 497 callback, 0)); |
| 498 return; |
| 499 } |
| 500 |
| 433 state_ = STATE_IO_PENDING; | 501 state_ = STATE_IO_PENDING; |
| 434 if (backend_) | 502 if (backend_) |
| 435 backend_->index()->UseIfExists(key_); | 503 backend_->index()->UseIfExists(key_); |
| 436 | 504 |
| 437 scoped_ptr<uint32> read_crc32(new uint32()); | 505 scoped_ptr<uint32> read_crc32(new uint32()); |
| 438 scoped_ptr<int> result(new int()); | 506 scoped_ptr<int> result(new int()); |
| 439 Closure task = base::Bind(&SimpleSynchronousEntry::ReadData, | 507 Closure task = base::Bind(&SimpleSynchronousEntry::ReadData, |
| 440 base::Unretained(synchronous_entry_), | 508 base::Unretained(synchronous_entry_), |
| 441 stream_index, offset, make_scoped_refptr(buf), | 509 stream_index, offset, make_scoped_refptr(buf), |
| 442 buf_len, read_crc32.get(), result.get()); | 510 buf_len, read_crc32.get(), result.get()); |
| 443 Closure reply = base::Bind(&SimpleEntryImpl::ReadOperationComplete, this, | 511 Closure reply = base::Bind(&SimpleEntryImpl::ReadOperationComplete, this, |
| 444 stream_index, offset, callback, | 512 stream_index, offset, callback, |
| 445 base::Passed(&read_crc32), base::Passed(&result)); | 513 base::Passed(&read_crc32), base::Passed(&result)); |
| 446 WorkerPool::PostTaskAndReply(FROM_HERE, task, reply, true); | 514 WorkerPool::PostTaskAndReply(FROM_HERE, task, reply, true); |
| 447 } | 515 } |
| 448 | 516 |
| 449 void SimpleEntryImpl::WriteDataInternal(int stream_index, | 517 void SimpleEntryImpl::WriteDataInternal(int stream_index, |
| 450 int offset, | 518 int offset, |
| 451 net::IOBuffer* buf, | 519 net::IOBuffer* buf, |
| 452 int buf_len, | 520 int buf_len, |
| 453 const CompletionCallback& callback, | 521 const CompletionCallback& callback, |
| 454 bool truncate) { | 522 bool truncate) { |
| 455 DCHECK(io_thread_checker_.CalledOnValidThread()); | 523 DCHECK(io_thread_checker_.CalledOnValidThread()); |
| 524 ScopedOperationRunner operation_runner(this); |
| 525 if (state_ == STATE_FAILURE || state_ == STATE_UNINITIALIZED) { |
| 526 if (!callback.is_null()) { |
| 527 // We need to posttask so that we don't go in a loop when we call the |
| 528 // callback directly. |
| 529 MessageLoopProxy::current()->PostTask(FROM_HERE, base::Bind( |
| 530 callback, net::ERR_FAILED)); |
| 531 } |
| 532 // |this| may be destroyed after return here. |
| 533 return; |
| 534 } |
| 456 DCHECK_EQ(STATE_READY, state_); | 535 DCHECK_EQ(STATE_READY, state_); |
| 457 state_ = STATE_IO_PENDING; | 536 state_ = STATE_IO_PENDING; |
| 458 if (backend_) | 537 if (backend_) |
| 459 backend_->index()->UseIfExists(key_); | 538 backend_->index()->UseIfExists(key_); |
| 460 // It is easy to incrementally compute the CRC from [0 .. |offset + buf_len|) | 539 // It is easy to incrementally compute the CRC from [0 .. |offset + buf_len|) |
| 461 // if |offset == 0| or we have already computed the CRC for [0 .. offset). | 540 // if |offset == 0| or we have already computed the CRC for [0 .. offset). |
| 462 // We rely on most write operations being sequential, start to end to compute | 541 // We rely on most write operations being sequential, start to end to compute |
| 463 // the crc of the data. When we write to an entry and close without having | 542 // the crc of the data. When we write to an entry and close without having |
| 464 // done a sequential write, we don't check the CRC on read. | 543 // done a sequential write, we don't check the CRC on read. |
| 465 if (offset == 0 || crc32s_end_offset_[stream_index] == offset) { | 544 if (offset == 0 || crc32s_end_offset_[stream_index] == offset) { |
| (...skipping 22 matching lines...) Expand all Loading... |
| 488 void SimpleEntryImpl::CreationOperationComplete( | 567 void SimpleEntryImpl::CreationOperationComplete( |
| 489 const CompletionCallback& completion_callback, | 568 const CompletionCallback& completion_callback, |
| 490 const base::TimeTicks& start_time, | 569 const base::TimeTicks& start_time, |
| 491 scoped_ptr<SimpleSynchronousEntry*> in_sync_entry, | 570 scoped_ptr<SimpleSynchronousEntry*> in_sync_entry, |
| 492 scoped_ptr<int> in_result, | 571 scoped_ptr<int> in_result, |
| 493 Entry** out_entry) { | 572 Entry** out_entry) { |
| 494 DCHECK(io_thread_checker_.CalledOnValidThread()); | 573 DCHECK(io_thread_checker_.CalledOnValidThread()); |
| 495 DCHECK_EQ(state_, STATE_IO_PENDING); | 574 DCHECK_EQ(state_, STATE_IO_PENDING); |
| 496 DCHECK(in_sync_entry); | 575 DCHECK(in_sync_entry); |
| 497 DCHECK(in_result); | 576 DCHECK(in_result); |
| 498 | |
| 499 ScopedOperationRunner operation_runner(this); | 577 ScopedOperationRunner operation_runner(this); |
| 500 | |
| 501 UMA_HISTOGRAM_BOOLEAN( | 578 UMA_HISTOGRAM_BOOLEAN( |
| 502 "SimpleCache.EntryCreationResult", *in_result == net::OK); | 579 "SimpleCache.EntryCreationResult", *in_result == net::OK); |
| 503 if (*in_result != net::OK) { | 580 if (*in_result != net::OK) { |
| 504 if (*in_result!= net::ERR_FILE_EXISTS) | 581 if (*in_result!= net::ERR_FILE_EXISTS) |
| 505 MarkAsDoomed(); | 582 MarkAsDoomed(); |
| 583 if (!completion_callback.is_null()) { |
| 584 MessageLoopProxy::current()->PostTask(FROM_HERE, base::Bind( |
| 585 completion_callback, net::ERR_FAILED)); |
| 586 } |
| 506 MakeUninitialized(); | 587 MakeUninitialized(); |
| 507 completion_callback.Run(net::ERR_FAILED); | 588 state_ = STATE_FAILURE; |
| 508 return; | 589 return; |
| 509 } | 590 } |
| 591 // If out_entry is NULL, it means we already called ReturnEntryToCaller from |
| 592 // the optimistic Create case. |
| 593 if (out_entry) |
| 594 ReturnEntryToCaller(out_entry); |
| 595 |
| 510 state_ = STATE_READY; | 596 state_ = STATE_READY; |
| 511 synchronous_entry_ = *in_sync_entry; | 597 synchronous_entry_ = *in_sync_entry; |
| 512 SetSynchronousData(); | 598 SetSynchronousData(); |
| 513 ReturnEntryToCaller(out_entry); | |
| 514 UMA_HISTOGRAM_TIMES("SimpleCache.EntryCreationTime", | 599 UMA_HISTOGRAM_TIMES("SimpleCache.EntryCreationTime", |
| 515 (base::TimeTicks::Now() - start_time)); | 600 (base::TimeTicks::Now() - start_time)); |
| 516 completion_callback.Run(net::OK); | 601 |
| 602 if (!completion_callback.is_null()) { |
| 603 MessageLoopProxy::current()->PostTask(FROM_HERE, base::Bind( |
| 604 completion_callback, net::OK)); |
| 605 } |
| 517 } | 606 } |
| 518 | 607 |
| 519 void SimpleEntryImpl::EntryOperationComplete( | 608 void SimpleEntryImpl::EntryOperationComplete( |
| 520 int stream_index, | 609 int stream_index, |
| 521 const CompletionCallback& completion_callback, | 610 const CompletionCallback& completion_callback, |
| 522 scoped_ptr<int> result) { | 611 scoped_ptr<int> result) { |
| 523 DCHECK(io_thread_checker_.CalledOnValidThread()); | 612 DCHECK(io_thread_checker_.CalledOnValidThread()); |
| 524 DCHECK(synchronous_entry_); | 613 DCHECK(synchronous_entry_); |
| 525 DCHECK_EQ(STATE_IO_PENDING, state_); | 614 DCHECK_EQ(STATE_IO_PENDING, state_); |
| 526 DCHECK(result); | 615 DCHECK(result); |
| 527 | |
| 528 state_ = STATE_READY; | 616 state_ = STATE_READY; |
| 529 | |
| 530 if (*result < 0) { | 617 if (*result < 0) { |
| 531 MarkAsDoomed(); | 618 MarkAsDoomed(); |
| 619 state_ = STATE_FAILURE; |
| 532 crc32s_end_offset_[stream_index] = 0; | 620 crc32s_end_offset_[stream_index] = 0; |
| 621 } else { |
| 622 SetSynchronousData(); |
| 533 } | 623 } |
| 534 SetSynchronousData(); | 624 |
| 535 completion_callback.Run(*result); | 625 if (!completion_callback.is_null()) { |
| 626 MessageLoopProxy::current()->PostTask(FROM_HERE, base::Bind( |
| 627 completion_callback, *result)); |
| 628 } |
| 536 RunNextOperationIfNeeded(); | 629 RunNextOperationIfNeeded(); |
| 537 } | 630 } |
| 538 | 631 |
| 539 void SimpleEntryImpl::ReadOperationComplete( | 632 void SimpleEntryImpl::ReadOperationComplete( |
| 540 int stream_index, | 633 int stream_index, |
| 541 int offset, | 634 int offset, |
| 542 const CompletionCallback& completion_callback, | 635 const CompletionCallback& completion_callback, |
| 543 scoped_ptr<uint32> read_crc32, | 636 scoped_ptr<uint32> read_crc32, |
| 544 scoped_ptr<int> result) { | 637 scoped_ptr<int> result) { |
| 545 DCHECK(io_thread_checker_.CalledOnValidThread()); | 638 DCHECK(io_thread_checker_.CalledOnValidThread()); |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 591 DCHECK_EQ(STATE_IO_PENDING, state_); | 684 DCHECK_EQ(STATE_IO_PENDING, state_); |
| 592 DCHECK(result); | 685 DCHECK(result); |
| 593 if (*result == net::OK) | 686 if (*result == net::OK) |
| 594 *result = orig_result; | 687 *result = orig_result; |
| 595 EntryOperationComplete(stream_index, completion_callback, result.Pass()); | 688 EntryOperationComplete(stream_index, completion_callback, result.Pass()); |
| 596 } | 689 } |
| 597 | 690 |
| 598 void SimpleEntryImpl::CloseOperationComplete() { | 691 void SimpleEntryImpl::CloseOperationComplete() { |
| 599 DCHECK(!synchronous_entry_); | 692 DCHECK(!synchronous_entry_); |
| 600 DCHECK_EQ(0, open_count_); | 693 DCHECK_EQ(0, open_count_); |
| 601 DCHECK_EQ(STATE_IO_PENDING, state_); | 694 DCHECK(STATE_IO_PENDING == state_ || STATE_FAILURE == state_); |
| 602 | |
| 603 MakeUninitialized(); | 695 MakeUninitialized(); |
| 604 RunNextOperationIfNeeded(); | 696 RunNextOperationIfNeeded(); |
| 605 } | 697 } |
| 606 | 698 |
| 607 void SimpleEntryImpl::SetSynchronousData() { | 699 void SimpleEntryImpl::SetSynchronousData() { |
| 608 DCHECK(io_thread_checker_.CalledOnValidThread()); | 700 DCHECK(io_thread_checker_.CalledOnValidThread()); |
| 701 DCHECK(synchronous_entry_); |
| 609 DCHECK_EQ(STATE_READY, state_); | 702 DCHECK_EQ(STATE_READY, state_); |
| 610 // TODO(felipeg): These copies to avoid data races are not optimal. While | 703 // TODO(felipeg): These copies to avoid data races are not optimal. While |
| 611 // adding an IO thread index (for fast misses etc...), we can store this data | 704 // adding an IO thread index (for fast misses etc...), we can store this data |
| 612 // in that structure. This also solves problems with last_used() on ext4 | 705 // in that structure. This also solves problems with last_used() on ext4 |
| 613 // filesystems not being accurate. | 706 // filesystems not being accurate. |
| 614 last_used_ = synchronous_entry_->last_used(); | 707 last_used_ = synchronous_entry_->last_used(); |
| 615 last_modified_ = synchronous_entry_->last_modified(); | 708 last_modified_ = synchronous_entry_->last_modified(); |
| 616 for (int i = 0; i < kSimpleEntryFileCount; ++i) | 709 for (int i = 0; i < kSimpleEntryFileCount; ++i) |
| 617 data_size_[i] = synchronous_entry_->data_size(i); | 710 data_size_[i] = synchronous_entry_->data_size(i); |
| 618 if (backend_) | 711 if (backend_) |
| 619 backend_->index()->UpdateEntrySize(key_, synchronous_entry_->GetFileSize()); | 712 backend_->index()->UpdateEntrySize(key_, synchronous_entry_->GetFileSize()); |
| 620 } | 713 } |
| 621 | 714 |
| 622 } // namespace disk_cache | 715 } // namespace disk_cache |
| OLD | NEW |