• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
3 // found in the LICENSE file.
4 
5 #include "net/disk_cache/simple/simple_entry_impl.h"
6 
7 #include <algorithm>
8 #include <cstring>
9 #include <vector>
10 
11 #include "base/bind.h"
12 #include "base/bind_helpers.h"
13 #include "base/callback.h"
14 #include "base/location.h"
15 #include "base/logging.h"
16 #include "base/single_thread_task_runner.h"
17 #include "base/task_runner.h"
18 #include "base/task_runner_util.h"
19 #include "base/thread_task_runner_handle.h"
20 #include "base/time/time.h"
21 #include "net/base/io_buffer.h"
22 #include "net/base/net_errors.h"
23 #include "net/disk_cache/net_log_parameters.h"
24 #include "net/disk_cache/simple/simple_backend_impl.h"
25 #include "net/disk_cache/simple/simple_histogram_macros.h"
26 #include "net/disk_cache/simple/simple_index.h"
27 #include "net/disk_cache/simple/simple_net_log_parameters.h"
28 #include "net/disk_cache/simple/simple_synchronous_entry.h"
29 #include "net/disk_cache/simple/simple_util.h"
30 #include "third_party/zlib/zlib.h"
31 
32 namespace disk_cache {
33 namespace {
34 
35 // An entry can store sparse data taking up to 1 / kMaxSparseDataSizeDivisor of
36 // the cache.
37 const int64 kMaxSparseDataSizeDivisor = 10;
38 
39 // Used in histograms, please only add entries at the end.
40 enum ReadResult {
41   READ_RESULT_SUCCESS = 0,
42   READ_RESULT_INVALID_ARGUMENT = 1,
43   READ_RESULT_NONBLOCK_EMPTY_RETURN = 2,
44   READ_RESULT_BAD_STATE = 3,
45   READ_RESULT_FAST_EMPTY_RETURN = 4,
46   READ_RESULT_SYNC_READ_FAILURE = 5,
47   READ_RESULT_SYNC_CHECKSUM_FAILURE = 6,
48   READ_RESULT_MAX = 7,
49 };
50 
51 // Used in histograms, please only add entries at the end.
52 enum WriteResult {
53   WRITE_RESULT_SUCCESS = 0,
54   WRITE_RESULT_INVALID_ARGUMENT = 1,
55   WRITE_RESULT_OVER_MAX_SIZE = 2,
56   WRITE_RESULT_BAD_STATE = 3,
57   WRITE_RESULT_SYNC_WRITE_FAILURE = 4,
58   WRITE_RESULT_FAST_EMPTY_RETURN = 5,
59   WRITE_RESULT_MAX = 6,
60 };
61 
62 // Used in histograms, please only add entries at the end.
63 enum HeaderSizeChange {
64   HEADER_SIZE_CHANGE_INITIAL,
65   HEADER_SIZE_CHANGE_SAME,
66   HEADER_SIZE_CHANGE_INCREASE,
67   HEADER_SIZE_CHANGE_DECREASE,
68   HEADER_SIZE_CHANGE_UNEXPECTED_WRITE,
69   HEADER_SIZE_CHANGE_MAX
70 };
71 
RecordReadResult(net::CacheType cache_type,ReadResult result)72 void RecordReadResult(net::CacheType cache_type, ReadResult result) {
73   SIMPLE_CACHE_UMA(ENUMERATION,
74                    "ReadResult", cache_type, result, READ_RESULT_MAX);
75 }
76 
RecordWriteResult(net::CacheType cache_type,WriteResult result)77 void RecordWriteResult(net::CacheType cache_type, WriteResult result) {
78   SIMPLE_CACHE_UMA(ENUMERATION,
79                    "WriteResult2", cache_type, result, WRITE_RESULT_MAX);
80 }
81 
82 // TODO(ttuttle): Consider removing this once we have a good handle on header
83 // size changes.
RecordHeaderSizeChange(net::CacheType cache_type,int old_size,int new_size)84 void RecordHeaderSizeChange(net::CacheType cache_type,
85                             int old_size, int new_size) {
86   HeaderSizeChange size_change;
87 
88   SIMPLE_CACHE_UMA(COUNTS_10000, "HeaderSize", cache_type, new_size);
89 
90   if (old_size == 0) {
91     size_change = HEADER_SIZE_CHANGE_INITIAL;
92   } else if (new_size == old_size) {
93     size_change = HEADER_SIZE_CHANGE_SAME;
94   } else if (new_size > old_size) {
95     int delta = new_size - old_size;
96     SIMPLE_CACHE_UMA(COUNTS_10000,
97                      "HeaderSizeIncreaseAbsolute", cache_type, delta);
98     SIMPLE_CACHE_UMA(PERCENTAGE,
99                      "HeaderSizeIncreasePercentage", cache_type,
100                      delta * 100 / old_size);
101     size_change = HEADER_SIZE_CHANGE_INCREASE;
102   } else {  // new_size < old_size
103     int delta = old_size - new_size;
104     SIMPLE_CACHE_UMA(COUNTS_10000,
105                      "HeaderSizeDecreaseAbsolute", cache_type, delta);
106     SIMPLE_CACHE_UMA(PERCENTAGE,
107                      "HeaderSizeDecreasePercentage", cache_type,
108                      delta * 100 / old_size);
109     size_change = HEADER_SIZE_CHANGE_DECREASE;
110   }
111 
112   SIMPLE_CACHE_UMA(ENUMERATION,
113                    "HeaderSizeChange", cache_type,
114                    size_change, HEADER_SIZE_CHANGE_MAX);
115 }
116 
RecordUnexpectedStream0Write(net::CacheType cache_type)117 void RecordUnexpectedStream0Write(net::CacheType cache_type) {
118   SIMPLE_CACHE_UMA(ENUMERATION,
119                    "HeaderSizeChange", cache_type,
120                    HEADER_SIZE_CHANGE_UNEXPECTED_WRITE, HEADER_SIZE_CHANGE_MAX);
121 }
122 
123 int g_open_entry_count = 0;
124 
AdjustOpenEntryCountBy(net::CacheType cache_type,int offset)125 void AdjustOpenEntryCountBy(net::CacheType cache_type, int offset) {
126   g_open_entry_count += offset;
127   SIMPLE_CACHE_UMA(COUNTS_10000,
128                    "GlobalOpenEntryCount", cache_type, g_open_entry_count);
129 }
130 
InvokeCallbackIfBackendIsAlive(const base::WeakPtr<SimpleBackendImpl> & backend,const net::CompletionCallback & completion_callback,int result)131 void InvokeCallbackIfBackendIsAlive(
132     const base::WeakPtr<SimpleBackendImpl>& backend,
133     const net::CompletionCallback& completion_callback,
134     int result) {
135   DCHECK(!completion_callback.is_null());
136   if (!backend.get())
137     return;
138   completion_callback.Run(result);
139 }
140 
141 }  // namespace
142 
143 using base::Closure;
144 using base::FilePath;
145 using base::MessageLoopProxy;
146 using base::Time;
147 using base::TaskRunner;
148 
149 // A helper class to insure that RunNextOperationIfNeeded() is called when
150 // exiting the current stack frame.
151 class SimpleEntryImpl::ScopedOperationRunner {
152  public:
ScopedOperationRunner(SimpleEntryImpl * entry)153   explicit ScopedOperationRunner(SimpleEntryImpl* entry) : entry_(entry) {
154   }
155 
~ScopedOperationRunner()156   ~ScopedOperationRunner() {
157     entry_->RunNextOperationIfNeeded();
158   }
159 
160  private:
161   SimpleEntryImpl* const entry_;
162 };
163 
~ActiveEntryProxy()164 SimpleEntryImpl::ActiveEntryProxy::~ActiveEntryProxy() {}
165 
SimpleEntryImpl(net::CacheType cache_type,const FilePath & path,const uint64 entry_hash,OperationsMode operations_mode,SimpleBackendImpl * backend,net::NetLog * net_log)166 SimpleEntryImpl::SimpleEntryImpl(net::CacheType cache_type,
167                                  const FilePath& path,
168                                  const uint64 entry_hash,
169                                  OperationsMode operations_mode,
170                                  SimpleBackendImpl* backend,
171                                  net::NetLog* net_log)
172     : backend_(backend->AsWeakPtr()),
173       cache_type_(cache_type),
174       worker_pool_(backend->worker_pool()),
175       path_(path),
176       entry_hash_(entry_hash),
177       use_optimistic_operations_(operations_mode == OPTIMISTIC_OPERATIONS),
178       last_used_(Time::Now()),
179       last_modified_(last_used_),
180       sparse_data_size_(0),
181       open_count_(0),
182       doomed_(false),
183       state_(STATE_UNINITIALIZED),
184       synchronous_entry_(NULL),
185       net_log_(net::BoundNetLog::Make(
186           net_log, net::NetLog::SOURCE_DISK_CACHE_ENTRY)),
187       stream_0_data_(new net::GrowableIOBuffer()) {
188   COMPILE_ASSERT(arraysize(data_size_) == arraysize(crc32s_end_offset_),
189                  arrays_should_be_same_size);
190   COMPILE_ASSERT(arraysize(data_size_) == arraysize(crc32s_),
191                  arrays_should_be_same_size);
192   COMPILE_ASSERT(arraysize(data_size_) == arraysize(have_written_),
193                  arrays_should_be_same_size);
194   COMPILE_ASSERT(arraysize(data_size_) == arraysize(crc_check_state_),
195                  arrays_should_be_same_size);
196   MakeUninitialized();
197   net_log_.BeginEvent(net::NetLog::TYPE_SIMPLE_CACHE_ENTRY,
198       CreateNetLogSimpleEntryConstructionCallback(this));
199 }
200 
SetActiveEntryProxy(scoped_ptr<ActiveEntryProxy> active_entry_proxy)201 void SimpleEntryImpl::SetActiveEntryProxy(
202     scoped_ptr<ActiveEntryProxy> active_entry_proxy) {
203   DCHECK(!active_entry_proxy_);
204   active_entry_proxy_.reset(active_entry_proxy.release());
205 }
206 
OpenEntry(Entry ** out_entry,const CompletionCallback & callback)207 int SimpleEntryImpl::OpenEntry(Entry** out_entry,
208                                const CompletionCallback& callback) {
209   DCHECK(backend_.get());
210 
211   net_log_.AddEvent(net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_OPEN_CALL);
212 
213   bool have_index = backend_->index()->initialized();
214   // This enumeration is used in histograms, add entries only at end.
215   enum OpenEntryIndexEnum {
216     INDEX_NOEXIST = 0,
217     INDEX_MISS = 1,
218     INDEX_HIT = 2,
219     INDEX_MAX = 3,
220   };
221   OpenEntryIndexEnum open_entry_index_enum = INDEX_NOEXIST;
222   if (have_index) {
223     if (backend_->index()->Has(entry_hash_))
224       open_entry_index_enum = INDEX_HIT;
225     else
226       open_entry_index_enum = INDEX_MISS;
227   }
228   SIMPLE_CACHE_UMA(ENUMERATION,
229                    "OpenEntryIndexState", cache_type_,
230                    open_entry_index_enum, INDEX_MAX);
231 
232   // If entry is not known to the index, initiate fast failover to the network.
233   if (open_entry_index_enum == INDEX_MISS) {
234     net_log_.AddEventWithNetErrorCode(
235         net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_OPEN_END,
236         net::ERR_FAILED);
237     return net::ERR_FAILED;
238   }
239 
240   pending_operations_.push(SimpleEntryOperation::OpenOperation(
241       this, have_index, callback, out_entry));
242   RunNextOperationIfNeeded();
243   return net::ERR_IO_PENDING;
244 }
245 
CreateEntry(Entry ** out_entry,const CompletionCallback & callback)246 int SimpleEntryImpl::CreateEntry(Entry** out_entry,
247                                  const CompletionCallback& callback) {
248   DCHECK(backend_.get());
249   DCHECK_EQ(entry_hash_, simple_util::GetEntryHashKey(key_));
250 
251   net_log_.AddEvent(net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_CREATE_CALL);
252 
253   bool have_index = backend_->index()->initialized();
254   int ret_value = net::ERR_FAILED;
255   if (use_optimistic_operations_ &&
256       state_ == STATE_UNINITIALIZED && pending_operations_.size() == 0) {
257     net_log_.AddEvent(net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_CREATE_OPTIMISTIC);
258 
259     ReturnEntryToCaller(out_entry);
260     pending_operations_.push(SimpleEntryOperation::CreateOperation(
261         this, have_index, CompletionCallback(), static_cast<Entry**>(NULL)));
262     ret_value = net::OK;
263   } else {
264     pending_operations_.push(SimpleEntryOperation::CreateOperation(
265         this, have_index, callback, out_entry));
266     ret_value = net::ERR_IO_PENDING;
267   }
268 
269   // We insert the entry in the index before creating the entry files in the
270   // SimpleSynchronousEntry, because this way the worst scenario is when we
271   // have the entry in the index but we don't have the created files yet, this
272   // way we never leak files. CreationOperationComplete will remove the entry
273   // from the index if the creation fails.
274   backend_->index()->Insert(entry_hash_);
275 
276   RunNextOperationIfNeeded();
277   return ret_value;
278 }
279 
DoomEntry(const CompletionCallback & callback)280 int SimpleEntryImpl::DoomEntry(const CompletionCallback& callback) {
281   if (doomed_)
282     return net::OK;
283   net_log_.AddEvent(net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_DOOM_CALL);
284   net_log_.AddEvent(net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_DOOM_BEGIN);
285 
286   MarkAsDoomed();
287   if (backend_.get())
288     backend_->OnDoomStart(entry_hash_);
289   pending_operations_.push(SimpleEntryOperation::DoomOperation(this, callback));
290   RunNextOperationIfNeeded();
291   return net::ERR_IO_PENDING;
292 }
293 
SetKey(const std::string & key)294 void SimpleEntryImpl::SetKey(const std::string& key) {
295   key_ = key;
296   net_log_.AddEvent(net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_SET_KEY,
297       net::NetLog::StringCallback("key", &key));
298 }
299 
Doom()300 void SimpleEntryImpl::Doom() {
301   DoomEntry(CompletionCallback());
302 }
303 
Close()304 void SimpleEntryImpl::Close() {
305   DCHECK(io_thread_checker_.CalledOnValidThread());
306   DCHECK_LT(0, open_count_);
307 
308   net_log_.AddEvent(net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_CLOSE_CALL);
309 
310   if (--open_count_ > 0) {
311     DCHECK(!HasOneRef());
312     Release();  // Balanced in ReturnEntryToCaller().
313     return;
314   }
315 
316   pending_operations_.push(SimpleEntryOperation::CloseOperation(this));
317   DCHECK(!HasOneRef());
318   Release();  // Balanced in ReturnEntryToCaller().
319   RunNextOperationIfNeeded();
320 }
321 
GetKey() const322 std::string SimpleEntryImpl::GetKey() const {
323   DCHECK(io_thread_checker_.CalledOnValidThread());
324   return key_;
325 }
326 
GetLastUsed() const327 Time SimpleEntryImpl::GetLastUsed() const {
328   DCHECK(io_thread_checker_.CalledOnValidThread());
329   return last_used_;
330 }
331 
GetLastModified() const332 Time SimpleEntryImpl::GetLastModified() const {
333   DCHECK(io_thread_checker_.CalledOnValidThread());
334   return last_modified_;
335 }
336 
GetDataSize(int stream_index) const337 int32 SimpleEntryImpl::GetDataSize(int stream_index) const {
338   DCHECK(io_thread_checker_.CalledOnValidThread());
339   DCHECK_LE(0, data_size_[stream_index]);
340   return data_size_[stream_index];
341 }
342 
ReadData(int stream_index,int offset,net::IOBuffer * buf,int buf_len,const CompletionCallback & callback)343 int SimpleEntryImpl::ReadData(int stream_index,
344                               int offset,
345                               net::IOBuffer* buf,
346                               int buf_len,
347                               const CompletionCallback& callback) {
348   DCHECK(io_thread_checker_.CalledOnValidThread());
349 
350   if (net_log_.IsLogging()) {
351     net_log_.AddEvent(net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_READ_CALL,
352         CreateNetLogReadWriteDataCallback(stream_index, offset, buf_len,
353                                           false));
354   }
355 
356   if (stream_index < 0 || stream_index >= kSimpleEntryStreamCount ||
357       buf_len < 0) {
358     if (net_log_.IsLogging()) {
359       net_log_.AddEvent(net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_READ_END,
360           CreateNetLogReadWriteCompleteCallback(net::ERR_INVALID_ARGUMENT));
361     }
362 
363     RecordReadResult(cache_type_, READ_RESULT_INVALID_ARGUMENT);
364     return net::ERR_INVALID_ARGUMENT;
365   }
366   if (pending_operations_.empty() && (offset >= GetDataSize(stream_index) ||
367                                       offset < 0 || !buf_len)) {
368     if (net_log_.IsLogging()) {
369       net_log_.AddEvent(net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_READ_END,
370           CreateNetLogReadWriteCompleteCallback(0));
371     }
372 
373     RecordReadResult(cache_type_, READ_RESULT_NONBLOCK_EMPTY_RETURN);
374     return 0;
375   }
376 
377   // TODO(clamy): return immediatly when reading from stream 0.
378 
379   // TODO(felipeg): Optimization: Add support for truly parallel read
380   // operations.
381   bool alone_in_queue =
382       pending_operations_.size() == 0 && state_ == STATE_READY;
383   pending_operations_.push(SimpleEntryOperation::ReadOperation(
384       this, stream_index, offset, buf_len, buf, callback, alone_in_queue));
385   RunNextOperationIfNeeded();
386   return net::ERR_IO_PENDING;
387 }
388 
WriteData(int stream_index,int offset,net::IOBuffer * buf,int buf_len,const CompletionCallback & callback,bool truncate)389 int SimpleEntryImpl::WriteData(int stream_index,
390                                int offset,
391                                net::IOBuffer* buf,
392                                int buf_len,
393                                const CompletionCallback& callback,
394                                bool truncate) {
395   DCHECK(io_thread_checker_.CalledOnValidThread());
396 
397   if (net_log_.IsLogging()) {
398     net_log_.AddEvent(
399         net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_WRITE_CALL,
400         CreateNetLogReadWriteDataCallback(stream_index, offset, buf_len,
401                                           truncate));
402   }
403 
404   if (stream_index < 0 || stream_index >= kSimpleEntryStreamCount ||
405       offset < 0 || buf_len < 0) {
406     if (net_log_.IsLogging()) {
407       net_log_.AddEvent(
408           net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_WRITE_END,
409           CreateNetLogReadWriteCompleteCallback(net::ERR_INVALID_ARGUMENT));
410     }
411     RecordWriteResult(cache_type_, WRITE_RESULT_INVALID_ARGUMENT);
412     return net::ERR_INVALID_ARGUMENT;
413   }
414   if (backend_.get() && offset + buf_len > backend_->GetMaxFileSize()) {
415     if (net_log_.IsLogging()) {
416       net_log_.AddEvent(
417           net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_WRITE_END,
418           CreateNetLogReadWriteCompleteCallback(net::ERR_FAILED));
419     }
420     RecordWriteResult(cache_type_, WRITE_RESULT_OVER_MAX_SIZE);
421     return net::ERR_FAILED;
422   }
423   ScopedOperationRunner operation_runner(this);
424 
425   // Stream 0 data is kept in memory, so can be written immediatly if there are
426   // no IO operations pending.
427   if (stream_index == 0 && state_ == STATE_READY &&
428       pending_operations_.size() == 0)
429     return SetStream0Data(buf, offset, buf_len, truncate);
430 
431   // We can only do optimistic Write if there is no pending operations, so
432   // that we are sure that the next call to RunNextOperationIfNeeded will
433   // actually run the write operation that sets the stream size. It also
434   // prevents from previous possibly-conflicting writes that could be stacked
435   // in the |pending_operations_|. We could optimize this for when we have
436   // only read operations enqueued.
437   const bool optimistic =
438       (use_optimistic_operations_ && state_ == STATE_READY &&
439        pending_operations_.size() == 0);
440   CompletionCallback op_callback;
441   scoped_refptr<net::IOBuffer> op_buf;
442   int ret_value = net::ERR_FAILED;
443   if (!optimistic) {
444     op_buf = buf;
445     op_callback = callback;
446     ret_value = net::ERR_IO_PENDING;
447   } else {
448     // TODO(gavinp,pasko): For performance, don't use a copy of an IOBuffer
449     // here to avoid paying the price of the RefCountedThreadSafe atomic
450     // operations.
451     if (buf) {
452       op_buf = new IOBuffer(buf_len);
453       memcpy(op_buf->data(), buf->data(), buf_len);
454     }
455     op_callback = CompletionCallback();
456     ret_value = buf_len;
457     if (net_log_.IsLogging()) {
458       net_log_.AddEvent(
459           net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_WRITE_OPTIMISTIC,
460           CreateNetLogReadWriteCompleteCallback(buf_len));
461     }
462   }
463 
464   pending_operations_.push(SimpleEntryOperation::WriteOperation(this,
465                                                                 stream_index,
466                                                                 offset,
467                                                                 buf_len,
468                                                                 op_buf.get(),
469                                                                 truncate,
470                                                                 optimistic,
471                                                                 op_callback));
472   return ret_value;
473 }
474 
ReadSparseData(int64 offset,net::IOBuffer * buf,int buf_len,const CompletionCallback & callback)475 int SimpleEntryImpl::ReadSparseData(int64 offset,
476                                     net::IOBuffer* buf,
477                                     int buf_len,
478                                     const CompletionCallback& callback) {
479   DCHECK(io_thread_checker_.CalledOnValidThread());
480 
481   ScopedOperationRunner operation_runner(this);
482   pending_operations_.push(SimpleEntryOperation::ReadSparseOperation(
483       this, offset, buf_len, buf, callback));
484   return net::ERR_IO_PENDING;
485 }
486 
WriteSparseData(int64 offset,net::IOBuffer * buf,int buf_len,const CompletionCallback & callback)487 int SimpleEntryImpl::WriteSparseData(int64 offset,
488                                      net::IOBuffer* buf,
489                                      int buf_len,
490                                      const CompletionCallback& callback) {
491   DCHECK(io_thread_checker_.CalledOnValidThread());
492 
493   ScopedOperationRunner operation_runner(this);
494   pending_operations_.push(SimpleEntryOperation::WriteSparseOperation(
495       this, offset, buf_len, buf, callback));
496   return net::ERR_IO_PENDING;
497 }
498 
GetAvailableRange(int64 offset,int len,int64 * start,const CompletionCallback & callback)499 int SimpleEntryImpl::GetAvailableRange(int64 offset,
500                                        int len,
501                                        int64* start,
502                                        const CompletionCallback& callback) {
503   DCHECK(io_thread_checker_.CalledOnValidThread());
504 
505   ScopedOperationRunner operation_runner(this);
506   pending_operations_.push(SimpleEntryOperation::GetAvailableRangeOperation(
507       this, offset, len, start, callback));
508   return net::ERR_IO_PENDING;
509 }
510 
CouldBeSparse() const511 bool SimpleEntryImpl::CouldBeSparse() const {
512   DCHECK(io_thread_checker_.CalledOnValidThread());
513   // TODO(ttuttle): Actually check.
514   return true;
515 }
516 
CancelSparseIO()517 void SimpleEntryImpl::CancelSparseIO() {
518   DCHECK(io_thread_checker_.CalledOnValidThread());
519   // The Simple Cache does not return distinct objects for the same non-doomed
520   // entry, so there's no need to coordinate which object is performing sparse
521   // I/O.  Therefore, CancelSparseIO and ReadyForSparseIO succeed instantly.
522 }
523 
ReadyForSparseIO(const CompletionCallback & callback)524 int SimpleEntryImpl::ReadyForSparseIO(const CompletionCallback& callback) {
525   DCHECK(io_thread_checker_.CalledOnValidThread());
526   // The simple Cache does not return distinct objects for the same non-doomed
527   // entry, so there's no need to coordinate which object is performing sparse
528   // I/O.  Therefore, CancelSparseIO and ReadyForSparseIO succeed instantly.
529   return net::OK;
530 }
531 
~SimpleEntryImpl()532 SimpleEntryImpl::~SimpleEntryImpl() {
533   DCHECK(io_thread_checker_.CalledOnValidThread());
534   DCHECK_EQ(0U, pending_operations_.size());
535   DCHECK(state_ == STATE_UNINITIALIZED || state_ == STATE_FAILURE);
536   DCHECK(!synchronous_entry_);
537   net_log_.EndEvent(net::NetLog::TYPE_SIMPLE_CACHE_ENTRY);
538 }
539 
PostClientCallback(const CompletionCallback & callback,int result)540 void SimpleEntryImpl::PostClientCallback(const CompletionCallback& callback,
541                                          int result) {
542   if (callback.is_null())
543     return;
544   // Note that the callback is posted rather than directly invoked to avoid
545   // reentrancy issues.
546   base::ThreadTaskRunnerHandle::Get()->PostTask(
547       FROM_HERE,
548       base::Bind(&InvokeCallbackIfBackendIsAlive, backend_, callback, result));
549 }
550 
MakeUninitialized()551 void SimpleEntryImpl::MakeUninitialized() {
552   state_ = STATE_UNINITIALIZED;
553   std::memset(crc32s_end_offset_, 0, sizeof(crc32s_end_offset_));
554   std::memset(crc32s_, 0, sizeof(crc32s_));
555   std::memset(have_written_, 0, sizeof(have_written_));
556   std::memset(data_size_, 0, sizeof(data_size_));
557   for (size_t i = 0; i < arraysize(crc_check_state_); ++i) {
558     crc_check_state_[i] = CRC_CHECK_NEVER_READ_AT_ALL;
559   }
560 }
561 
ReturnEntryToCaller(Entry ** out_entry)562 void SimpleEntryImpl::ReturnEntryToCaller(Entry** out_entry) {
563   DCHECK(out_entry);
564   ++open_count_;
565   AddRef();  // Balanced in Close()
566   if (!backend_.get()) {
567     // This method can be called when an asynchronous operation completed.
568     // If the backend no longer exists, the callback won't be invoked, and so we
569     // must close ourselves to avoid leaking. As well, there's no guarantee the
570     // client-provided pointer (|out_entry|) hasn't been freed, and no point
571     // dereferencing it, either.
572     Close();
573     return;
574   }
575   *out_entry = this;
576 }
577 
MarkAsDoomed()578 void SimpleEntryImpl::MarkAsDoomed() {
579   doomed_ = true;
580   if (!backend_.get())
581     return;
582   backend_->index()->Remove(entry_hash_);
583   active_entry_proxy_.reset();
584 }
585 
RunNextOperationIfNeeded()586 void SimpleEntryImpl::RunNextOperationIfNeeded() {
587   DCHECK(io_thread_checker_.CalledOnValidThread());
588   SIMPLE_CACHE_UMA(CUSTOM_COUNTS,
589                    "EntryOperationsPending", cache_type_,
590                    pending_operations_.size(), 0, 100, 20);
591   if (!pending_operations_.empty() && state_ != STATE_IO_PENDING) {
592     scoped_ptr<SimpleEntryOperation> operation(
593         new SimpleEntryOperation(pending_operations_.front()));
594     pending_operations_.pop();
595     switch (operation->type()) {
596       case SimpleEntryOperation::TYPE_OPEN:
597         OpenEntryInternal(operation->have_index(),
598                           operation->callback(),
599                           operation->out_entry());
600         break;
601       case SimpleEntryOperation::TYPE_CREATE:
602         CreateEntryInternal(operation->have_index(),
603                             operation->callback(),
604                             operation->out_entry());
605         break;
606       case SimpleEntryOperation::TYPE_CLOSE:
607         CloseInternal();
608         break;
609       case SimpleEntryOperation::TYPE_READ:
610         RecordReadIsParallelizable(*operation);
611         ReadDataInternal(operation->index(),
612                          operation->offset(),
613                          operation->buf(),
614                          operation->length(),
615                          operation->callback());
616         break;
617       case SimpleEntryOperation::TYPE_WRITE:
618         RecordWriteDependencyType(*operation);
619         WriteDataInternal(operation->index(),
620                           operation->offset(),
621                           operation->buf(),
622                           operation->length(),
623                           operation->callback(),
624                           operation->truncate());
625         break;
626       case SimpleEntryOperation::TYPE_READ_SPARSE:
627         ReadSparseDataInternal(operation->sparse_offset(),
628                                operation->buf(),
629                                operation->length(),
630                                operation->callback());
631         break;
632       case SimpleEntryOperation::TYPE_WRITE_SPARSE:
633         WriteSparseDataInternal(operation->sparse_offset(),
634                                 operation->buf(),
635                                 operation->length(),
636                                 operation->callback());
637         break;
638       case SimpleEntryOperation::TYPE_GET_AVAILABLE_RANGE:
639         GetAvailableRangeInternal(operation->sparse_offset(),
640                                   operation->length(),
641                                   operation->out_start(),
642                                   operation->callback());
643         break;
644       case SimpleEntryOperation::TYPE_DOOM:
645         DoomEntryInternal(operation->callback());
646         break;
647       default:
648         NOTREACHED();
649     }
650     // The operation is kept for histograms. Makes sure it does not leak
651     // resources.
652     executing_operation_.swap(operation);
653     executing_operation_->ReleaseReferences();
654     // |this| may have been deleted.
655   }
656 }
657 
OpenEntryInternal(bool have_index,const CompletionCallback & callback,Entry ** out_entry)658 void SimpleEntryImpl::OpenEntryInternal(bool have_index,
659                                         const CompletionCallback& callback,
660                                         Entry** out_entry) {
661   ScopedOperationRunner operation_runner(this);
662 
663   net_log_.AddEvent(net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_OPEN_BEGIN);
664 
665   if (state_ == STATE_READY) {
666     ReturnEntryToCaller(out_entry);
667     PostClientCallback(callback, net::OK);
668     net_log_.AddEvent(
669         net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_OPEN_END,
670         CreateNetLogSimpleEntryCreationCallback(this, net::OK));
671     return;
672   }
673   if (state_ == STATE_FAILURE) {
674     PostClientCallback(callback, net::ERR_FAILED);
675     net_log_.AddEvent(
676         net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_OPEN_END,
677         CreateNetLogSimpleEntryCreationCallback(this, net::ERR_FAILED));
678     return;
679   }
680 
681   DCHECK_EQ(STATE_UNINITIALIZED, state_);
682   DCHECK(!synchronous_entry_);
683   state_ = STATE_IO_PENDING;
684   const base::TimeTicks start_time = base::TimeTicks::Now();
685   scoped_ptr<SimpleEntryCreationResults> results(
686       new SimpleEntryCreationResults(
687           SimpleEntryStat(last_used_, last_modified_, data_size_,
688                           sparse_data_size_)));
689   Closure task = base::Bind(&SimpleSynchronousEntry::OpenEntry,
690                             cache_type_,
691                             path_,
692                             entry_hash_,
693                             have_index,
694                             results.get());
695   Closure reply = base::Bind(&SimpleEntryImpl::CreationOperationComplete,
696                              this,
697                              callback,
698                              start_time,
699                              base::Passed(&results),
700                              out_entry,
701                              net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_OPEN_END);
702   worker_pool_->PostTaskAndReply(FROM_HERE, task, reply);
703 }
704 
CreateEntryInternal(bool have_index,const CompletionCallback & callback,Entry ** out_entry)705 void SimpleEntryImpl::CreateEntryInternal(bool have_index,
706                                           const CompletionCallback& callback,
707                                           Entry** out_entry) {
708   ScopedOperationRunner operation_runner(this);
709 
710   net_log_.AddEvent(net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_CREATE_BEGIN);
711 
712   if (state_ != STATE_UNINITIALIZED) {
713     // There is already an active normal entry.
714     net_log_.AddEvent(
715         net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_CREATE_END,
716         CreateNetLogSimpleEntryCreationCallback(this, net::ERR_FAILED));
717     PostClientCallback(callback, net::ERR_FAILED);
718     return;
719   }
720   DCHECK_EQ(STATE_UNINITIALIZED, state_);
721   DCHECK(!synchronous_entry_);
722 
723   state_ = STATE_IO_PENDING;
724 
725   // Since we don't know the correct values for |last_used_| and
726   // |last_modified_| yet, we make this approximation.
727   last_used_ = last_modified_ = base::Time::Now();
728 
729   // If creation succeeds, we should mark all streams to be saved on close.
730   for (int i = 0; i < kSimpleEntryStreamCount; ++i)
731     have_written_[i] = true;
732 
733   const base::TimeTicks start_time = base::TimeTicks::Now();
734   scoped_ptr<SimpleEntryCreationResults> results(
735       new SimpleEntryCreationResults(
736           SimpleEntryStat(last_used_, last_modified_, data_size_,
737                           sparse_data_size_)));
738   Closure task = base::Bind(&SimpleSynchronousEntry::CreateEntry,
739                             cache_type_,
740                             path_,
741                             key_,
742                             entry_hash_,
743                             have_index,
744                             results.get());
745   Closure reply = base::Bind(&SimpleEntryImpl::CreationOperationComplete,
746                              this,
747                              callback,
748                              start_time,
749                              base::Passed(&results),
750                              out_entry,
751                              net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_CREATE_END);
752   worker_pool_->PostTaskAndReply(FROM_HERE, task, reply);
753 }
754 
CloseInternal()755 void SimpleEntryImpl::CloseInternal() {
756   DCHECK(io_thread_checker_.CalledOnValidThread());
757   typedef SimpleSynchronousEntry::CRCRecord CRCRecord;
758   scoped_ptr<std::vector<CRCRecord> >
759       crc32s_to_write(new std::vector<CRCRecord>());
760 
761   net_log_.AddEvent(net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_CLOSE_BEGIN);
762 
763   if (state_ == STATE_READY) {
764     DCHECK(synchronous_entry_);
765     state_ = STATE_IO_PENDING;
766     for (int i = 0; i < kSimpleEntryStreamCount; ++i) {
767       if (have_written_[i]) {
768         if (GetDataSize(i) == crc32s_end_offset_[i]) {
769           int32 crc = GetDataSize(i) == 0 ? crc32(0, Z_NULL, 0) : crc32s_[i];
770           crc32s_to_write->push_back(CRCRecord(i, true, crc));
771         } else {
772           crc32s_to_write->push_back(CRCRecord(i, false, 0));
773         }
774       }
775     }
776   } else {
777     DCHECK(STATE_UNINITIALIZED == state_ || STATE_FAILURE == state_);
778   }
779 
780   if (synchronous_entry_) {
781     Closure task =
782         base::Bind(&SimpleSynchronousEntry::Close,
783                    base::Unretained(synchronous_entry_),
784                    SimpleEntryStat(last_used_, last_modified_, data_size_,
785                                    sparse_data_size_),
786                    base::Passed(&crc32s_to_write),
787                    stream_0_data_);
788     Closure reply = base::Bind(&SimpleEntryImpl::CloseOperationComplete, this);
789     synchronous_entry_ = NULL;
790     worker_pool_->PostTaskAndReply(FROM_HERE, task, reply);
791 
792     for (int i = 0; i < kSimpleEntryStreamCount; ++i) {
793       if (!have_written_[i]) {
794         SIMPLE_CACHE_UMA(ENUMERATION,
795                          "CheckCRCResult", cache_type_,
796                          crc_check_state_[i], CRC_CHECK_MAX);
797       }
798     }
799   } else {
800     CloseOperationComplete();
801   }
802 }
803 
ReadDataInternal(int stream_index,int offset,net::IOBuffer * buf,int buf_len,const CompletionCallback & callback)804 void SimpleEntryImpl::ReadDataInternal(int stream_index,
805                                        int offset,
806                                        net::IOBuffer* buf,
807                                        int buf_len,
808                                        const CompletionCallback& callback) {
809   DCHECK(io_thread_checker_.CalledOnValidThread());
810   ScopedOperationRunner operation_runner(this);
811 
812   if (net_log_.IsLogging()) {
813     net_log_.AddEvent(
814         net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_READ_BEGIN,
815         CreateNetLogReadWriteDataCallback(stream_index, offset, buf_len,
816                                           false));
817   }
818 
819   if (state_ == STATE_FAILURE || state_ == STATE_UNINITIALIZED) {
820     if (!callback.is_null()) {
821       RecordReadResult(cache_type_, READ_RESULT_BAD_STATE);
822       // Note that the API states that client-provided callbacks for entry-level
823       // (i.e. non-backend) operations (e.g. read, write) are invoked even if
824       // the backend was already destroyed.
825       base::ThreadTaskRunnerHandle::Get()->PostTask(
826           FROM_HERE, base::Bind(callback, net::ERR_FAILED));
827     }
828     if (net_log_.IsLogging()) {
829       net_log_.AddEvent(
830           net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_READ_END,
831           CreateNetLogReadWriteCompleteCallback(net::ERR_FAILED));
832     }
833     return;
834   }
835   DCHECK_EQ(STATE_READY, state_);
836   if (offset >= GetDataSize(stream_index) || offset < 0 || !buf_len) {
837     RecordReadResult(cache_type_, READ_RESULT_FAST_EMPTY_RETURN);
838     // If there is nothing to read, we bail out before setting state_ to
839     // STATE_IO_PENDING.
840     if (!callback.is_null())
841       base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
842                                                     base::Bind(callback, 0));
843     return;
844   }
845 
846   buf_len = std::min(buf_len, GetDataSize(stream_index) - offset);
847 
848   // Since stream 0 data is kept in memory, it is read immediately.
849   if (stream_index == 0) {
850     int ret_value = ReadStream0Data(buf, offset, buf_len);
851     if (!callback.is_null()) {
852       base::ThreadTaskRunnerHandle::Get()->PostTask(
853           FROM_HERE, base::Bind(callback, ret_value));
854     }
855     return;
856   }
857 
858   state_ = STATE_IO_PENDING;
859   if (!doomed_ && backend_.get())
860     backend_->index()->UseIfExists(entry_hash_);
861 
862   scoped_ptr<uint32> read_crc32(new uint32());
863   scoped_ptr<int> result(new int());
864   scoped_ptr<SimpleEntryStat> entry_stat(
865       new SimpleEntryStat(last_used_, last_modified_, data_size_,
866                           sparse_data_size_));
867   Closure task = base::Bind(
868       &SimpleSynchronousEntry::ReadData,
869       base::Unretained(synchronous_entry_),
870       SimpleSynchronousEntry::EntryOperationData(stream_index, offset, buf_len),
871       make_scoped_refptr(buf),
872       read_crc32.get(),
873       entry_stat.get(),
874       result.get());
875   Closure reply = base::Bind(&SimpleEntryImpl::ReadOperationComplete,
876                              this,
877                              stream_index,
878                              offset,
879                              callback,
880                              base::Passed(&read_crc32),
881                              base::Passed(&entry_stat),
882                              base::Passed(&result));
883   worker_pool_->PostTaskAndReply(FROM_HERE, task, reply);
884 }
885 
WriteDataInternal(int stream_index,int offset,net::IOBuffer * buf,int buf_len,const CompletionCallback & callback,bool truncate)886 void SimpleEntryImpl::WriteDataInternal(int stream_index,
887                                        int offset,
888                                        net::IOBuffer* buf,
889                                        int buf_len,
890                                        const CompletionCallback& callback,
891                                        bool truncate) {
892   DCHECK(io_thread_checker_.CalledOnValidThread());
893   ScopedOperationRunner operation_runner(this);
894 
895   if (net_log_.IsLogging()) {
896     net_log_.AddEvent(
897         net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_WRITE_BEGIN,
898         CreateNetLogReadWriteDataCallback(stream_index, offset, buf_len,
899                                           truncate));
900   }
901 
902   if (state_ == STATE_FAILURE || state_ == STATE_UNINITIALIZED) {
903     RecordWriteResult(cache_type_, WRITE_RESULT_BAD_STATE);
904     if (net_log_.IsLogging()) {
905       net_log_.AddEvent(
906           net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_WRITE_END,
907           CreateNetLogReadWriteCompleteCallback(net::ERR_FAILED));
908     }
909     if (!callback.is_null()) {
910       base::ThreadTaskRunnerHandle::Get()->PostTask(
911           FROM_HERE, base::Bind(callback, net::ERR_FAILED));
912     }
913     // |this| may be destroyed after return here.
914     return;
915   }
916 
917   DCHECK_EQ(STATE_READY, state_);
918 
919   // Since stream 0 data is kept in memory, it will be written immediatly.
920   if (stream_index == 0) {
921     int ret_value = SetStream0Data(buf, offset, buf_len, truncate);
922     if (!callback.is_null()) {
923       base::ThreadTaskRunnerHandle::Get()->PostTask(
924           FROM_HERE, base::Bind(callback, ret_value));
925     }
926     return;
927   }
928 
929   // Ignore zero-length writes that do not change the file size.
930   if (buf_len == 0) {
931     int32 data_size = data_size_[stream_index];
932     if (truncate ? (offset == data_size) : (offset <= data_size)) {
933       RecordWriteResult(cache_type_, WRITE_RESULT_FAST_EMPTY_RETURN);
934       if (!callback.is_null()) {
935         base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
936                                                       base::Bind(callback, 0));
937       }
938       return;
939     }
940   }
941   state_ = STATE_IO_PENDING;
942   if (!doomed_ && backend_.get())
943     backend_->index()->UseIfExists(entry_hash_);
944 
945   AdvanceCrc(buf, offset, buf_len, stream_index);
946 
947   // |entry_stat| needs to be initialized before modifying |data_size_|.
948   scoped_ptr<SimpleEntryStat> entry_stat(
949       new SimpleEntryStat(last_used_, last_modified_, data_size_,
950                           sparse_data_size_));
951   if (truncate) {
952     data_size_[stream_index] = offset + buf_len;
953   } else {
954     data_size_[stream_index] = std::max(offset + buf_len,
955                                         GetDataSize(stream_index));
956   }
957 
958   // Since we don't know the correct values for |last_used_| and
959   // |last_modified_| yet, we make this approximation.
960   last_used_ = last_modified_ = base::Time::Now();
961 
962   have_written_[stream_index] = true;
963   // Writing on stream 1 affects the placement of stream 0 in the file, the EOF
964   // record will have to be rewritten.
965   if (stream_index == 1)
966     have_written_[0] = true;
967 
968   scoped_ptr<int> result(new int());
969   Closure task = base::Bind(&SimpleSynchronousEntry::WriteData,
970                             base::Unretained(synchronous_entry_),
971                             SimpleSynchronousEntry::EntryOperationData(
972                                 stream_index, offset, buf_len, truncate,
973                                 doomed_),
974                             make_scoped_refptr(buf),
975                             entry_stat.get(),
976                             result.get());
977   Closure reply = base::Bind(&SimpleEntryImpl::WriteOperationComplete,
978                              this,
979                              stream_index,
980                              callback,
981                              base::Passed(&entry_stat),
982                              base::Passed(&result));
983   worker_pool_->PostTaskAndReply(FROM_HERE, task, reply);
984 }
985 
ReadSparseDataInternal(int64 sparse_offset,net::IOBuffer * buf,int buf_len,const CompletionCallback & callback)986 void SimpleEntryImpl::ReadSparseDataInternal(
987     int64 sparse_offset,
988     net::IOBuffer* buf,
989     int buf_len,
990     const CompletionCallback& callback) {
991   DCHECK(io_thread_checker_.CalledOnValidThread());
992   ScopedOperationRunner operation_runner(this);
993 
994   DCHECK_EQ(STATE_READY, state_);
995   state_ = STATE_IO_PENDING;
996 
997   scoped_ptr<int> result(new int());
998   scoped_ptr<base::Time> last_used(new base::Time());
999   Closure task = base::Bind(&SimpleSynchronousEntry::ReadSparseData,
1000                             base::Unretained(synchronous_entry_),
1001                             SimpleSynchronousEntry::EntryOperationData(
1002                                 sparse_offset, buf_len),
1003                             make_scoped_refptr(buf),
1004                             last_used.get(),
1005                             result.get());
1006   Closure reply = base::Bind(&SimpleEntryImpl::ReadSparseOperationComplete,
1007                              this,
1008                              callback,
1009                              base::Passed(&last_used),
1010                              base::Passed(&result));
1011   worker_pool_->PostTaskAndReply(FROM_HERE, task, reply);
1012 }
1013 
WriteSparseDataInternal(int64 sparse_offset,net::IOBuffer * buf,int buf_len,const CompletionCallback & callback)1014 void SimpleEntryImpl::WriteSparseDataInternal(
1015     int64 sparse_offset,
1016     net::IOBuffer* buf,
1017     int buf_len,
1018     const CompletionCallback& callback) {
1019   DCHECK(io_thread_checker_.CalledOnValidThread());
1020   ScopedOperationRunner operation_runner(this);
1021 
1022   DCHECK_EQ(STATE_READY, state_);
1023   state_ = STATE_IO_PENDING;
1024 
1025   int64 max_sparse_data_size = kint64max;
1026   if (backend_.get()) {
1027     int64 max_cache_size = backend_->index()->max_size();
1028     max_sparse_data_size = max_cache_size / kMaxSparseDataSizeDivisor;
1029   }
1030 
1031   scoped_ptr<SimpleEntryStat> entry_stat(
1032       new SimpleEntryStat(last_used_, last_modified_, data_size_,
1033                           sparse_data_size_));
1034 
1035   last_used_ = last_modified_ = base::Time::Now();
1036 
1037   scoped_ptr<int> result(new int());
1038   Closure task = base::Bind(&SimpleSynchronousEntry::WriteSparseData,
1039                             base::Unretained(synchronous_entry_),
1040                             SimpleSynchronousEntry::EntryOperationData(
1041                                 sparse_offset, buf_len),
1042                             make_scoped_refptr(buf),
1043                             max_sparse_data_size,
1044                             entry_stat.get(),
1045                             result.get());
1046   Closure reply = base::Bind(&SimpleEntryImpl::WriteSparseOperationComplete,
1047                              this,
1048                              callback,
1049                              base::Passed(&entry_stat),
1050                              base::Passed(&result));
1051   worker_pool_->PostTaskAndReply(FROM_HERE, task, reply);
1052 }
1053 
GetAvailableRangeInternal(int64 sparse_offset,int len,int64 * out_start,const CompletionCallback & callback)1054 void SimpleEntryImpl::GetAvailableRangeInternal(
1055     int64 sparse_offset,
1056     int len,
1057     int64* out_start,
1058     const CompletionCallback& callback) {
1059   DCHECK(io_thread_checker_.CalledOnValidThread());
1060   ScopedOperationRunner operation_runner(this);
1061 
1062   DCHECK_EQ(STATE_READY, state_);
1063   state_ = STATE_IO_PENDING;
1064 
1065   scoped_ptr<int> result(new int());
1066   Closure task = base::Bind(&SimpleSynchronousEntry::GetAvailableRange,
1067                             base::Unretained(synchronous_entry_),
1068                             SimpleSynchronousEntry::EntryOperationData(
1069                                 sparse_offset, len),
1070                             out_start,
1071                             result.get());
1072   Closure reply = base::Bind(
1073       &SimpleEntryImpl::GetAvailableRangeOperationComplete,
1074       this,
1075       callback,
1076       base::Passed(&result));
1077   worker_pool_->PostTaskAndReply(FROM_HERE, task, reply);
1078 }
1079 
DoomEntryInternal(const CompletionCallback & callback)1080 void SimpleEntryImpl::DoomEntryInternal(const CompletionCallback& callback) {
1081   PostTaskAndReplyWithResult(
1082       worker_pool_.get(),
1083       FROM_HERE,
1084       base::Bind(&SimpleSynchronousEntry::DoomEntry, path_, entry_hash_),
1085       base::Bind(
1086           &SimpleEntryImpl::DoomOperationComplete, this, callback, state_));
1087   state_ = STATE_IO_PENDING;
1088 }
1089 
CreationOperationComplete(const CompletionCallback & completion_callback,const base::TimeTicks & start_time,scoped_ptr<SimpleEntryCreationResults> in_results,Entry ** out_entry,net::NetLog::EventType end_event_type)1090 void SimpleEntryImpl::CreationOperationComplete(
1091     const CompletionCallback& completion_callback,
1092     const base::TimeTicks& start_time,
1093     scoped_ptr<SimpleEntryCreationResults> in_results,
1094     Entry** out_entry,
1095     net::NetLog::EventType end_event_type) {
1096   DCHECK(io_thread_checker_.CalledOnValidThread());
1097   DCHECK_EQ(state_, STATE_IO_PENDING);
1098   DCHECK(in_results);
1099   ScopedOperationRunner operation_runner(this);
1100   SIMPLE_CACHE_UMA(BOOLEAN,
1101                    "EntryCreationResult", cache_type_,
1102                    in_results->result == net::OK);
1103   if (in_results->result != net::OK) {
1104     if (in_results->result != net::ERR_FILE_EXISTS)
1105       MarkAsDoomed();
1106 
1107     net_log_.AddEventWithNetErrorCode(end_event_type, net::ERR_FAILED);
1108     PostClientCallback(completion_callback, net::ERR_FAILED);
1109     MakeUninitialized();
1110     return;
1111   }
1112   // If out_entry is NULL, it means we already called ReturnEntryToCaller from
1113   // the optimistic Create case.
1114   if (out_entry)
1115     ReturnEntryToCaller(out_entry);
1116 
1117   state_ = STATE_READY;
1118   synchronous_entry_ = in_results->sync_entry;
1119   if (in_results->stream_0_data.get()) {
1120     stream_0_data_ = in_results->stream_0_data;
1121     // The crc was read in SimpleSynchronousEntry.
1122     crc_check_state_[0] = CRC_CHECK_DONE;
1123     crc32s_[0] = in_results->stream_0_crc32;
1124     crc32s_end_offset_[0] = in_results->entry_stat.data_size(0);
1125   }
1126   if (key_.empty()) {
1127     SetKey(synchronous_entry_->key());
1128   } else {
1129     // This should only be triggered when creating an entry. The key check in
1130     // the open case is handled in SimpleBackendImpl.
1131     DCHECK_EQ(key_, synchronous_entry_->key());
1132   }
1133   UpdateDataFromEntryStat(in_results->entry_stat);
1134   SIMPLE_CACHE_UMA(TIMES,
1135                    "EntryCreationTime", cache_type_,
1136                    (base::TimeTicks::Now() - start_time));
1137   AdjustOpenEntryCountBy(cache_type_, 1);
1138 
1139   net_log_.AddEvent(end_event_type);
1140   PostClientCallback(completion_callback, net::OK);
1141 }
1142 
EntryOperationComplete(const CompletionCallback & completion_callback,const SimpleEntryStat & entry_stat,scoped_ptr<int> result)1143 void SimpleEntryImpl::EntryOperationComplete(
1144     const CompletionCallback& completion_callback,
1145     const SimpleEntryStat& entry_stat,
1146     scoped_ptr<int> result) {
1147   DCHECK(io_thread_checker_.CalledOnValidThread());
1148   DCHECK(synchronous_entry_);
1149   DCHECK_EQ(STATE_IO_PENDING, state_);
1150   DCHECK(result);
1151   if (*result < 0) {
1152     state_ = STATE_FAILURE;
1153     MarkAsDoomed();
1154   } else {
1155     state_ = STATE_READY;
1156     UpdateDataFromEntryStat(entry_stat);
1157   }
1158 
1159   if (!completion_callback.is_null()) {
1160     base::ThreadTaskRunnerHandle::Get()->PostTask(
1161         FROM_HERE, base::Bind(completion_callback, *result));
1162   }
1163   RunNextOperationIfNeeded();
1164 }
1165 
ReadOperationComplete(int stream_index,int offset,const CompletionCallback & completion_callback,scoped_ptr<uint32> read_crc32,scoped_ptr<SimpleEntryStat> entry_stat,scoped_ptr<int> result)1166 void SimpleEntryImpl::ReadOperationComplete(
1167     int stream_index,
1168     int offset,
1169     const CompletionCallback& completion_callback,
1170     scoped_ptr<uint32> read_crc32,
1171     scoped_ptr<SimpleEntryStat> entry_stat,
1172     scoped_ptr<int> result) {
1173   DCHECK(io_thread_checker_.CalledOnValidThread());
1174   DCHECK(synchronous_entry_);
1175   DCHECK_EQ(STATE_IO_PENDING, state_);
1176   DCHECK(read_crc32);
1177   DCHECK(result);
1178 
1179   if (*result > 0 &&
1180       crc_check_state_[stream_index] == CRC_CHECK_NEVER_READ_AT_ALL) {
1181     crc_check_state_[stream_index] = CRC_CHECK_NEVER_READ_TO_END;
1182   }
1183 
1184   if (*result > 0 && crc32s_end_offset_[stream_index] == offset) {
1185     uint32 current_crc = offset == 0 ? crc32(0, Z_NULL, 0)
1186                                      : crc32s_[stream_index];
1187     crc32s_[stream_index] = crc32_combine(current_crc, *read_crc32, *result);
1188     crc32s_end_offset_[stream_index] += *result;
1189     if (!have_written_[stream_index] &&
1190         GetDataSize(stream_index) == crc32s_end_offset_[stream_index]) {
1191       // We have just read a file from start to finish, and so we have
1192       // computed a crc of the entire file. We can check it now. If a cache
1193       // entry has a single reader, the normal pattern is to read from start
1194       // to finish.
1195 
1196       // Other cases are possible. In the case of two readers on the same
1197       // entry, one reader can be behind the other. In this case we compute
1198       // the crc as the most advanced reader progresses, and check it for
1199       // both readers as they read the last byte.
1200 
1201       net_log_.AddEvent(net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_CHECKSUM_BEGIN);
1202 
1203       scoped_ptr<int> new_result(new int());
1204       Closure task = base::Bind(&SimpleSynchronousEntry::CheckEOFRecord,
1205                                 base::Unretained(synchronous_entry_),
1206                                 stream_index,
1207                                 *entry_stat,
1208                                 crc32s_[stream_index],
1209                                 new_result.get());
1210       Closure reply = base::Bind(&SimpleEntryImpl::ChecksumOperationComplete,
1211                                  this, *result, stream_index,
1212                                  completion_callback,
1213                                  base::Passed(&new_result));
1214       worker_pool_->PostTaskAndReply(FROM_HERE, task, reply);
1215       crc_check_state_[stream_index] = CRC_CHECK_DONE;
1216       return;
1217     }
1218   }
1219 
1220   if (*result < 0) {
1221     crc32s_end_offset_[stream_index] = 0;
1222   }
1223 
1224   if (*result < 0) {
1225     RecordReadResult(cache_type_, READ_RESULT_SYNC_READ_FAILURE);
1226   } else {
1227     RecordReadResult(cache_type_, READ_RESULT_SUCCESS);
1228     if (crc_check_state_[stream_index] == CRC_CHECK_NEVER_READ_TO_END &&
1229         offset + *result == GetDataSize(stream_index)) {
1230       crc_check_state_[stream_index] = CRC_CHECK_NOT_DONE;
1231     }
1232   }
1233   if (net_log_.IsLogging()) {
1234     net_log_.AddEvent(
1235         net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_READ_END,
1236         CreateNetLogReadWriteCompleteCallback(*result));
1237   }
1238 
1239   EntryOperationComplete(completion_callback, *entry_stat, result.Pass());
1240 }
1241 
WriteOperationComplete(int stream_index,const CompletionCallback & completion_callback,scoped_ptr<SimpleEntryStat> entry_stat,scoped_ptr<int> result)1242 void SimpleEntryImpl::WriteOperationComplete(
1243     int stream_index,
1244     const CompletionCallback& completion_callback,
1245     scoped_ptr<SimpleEntryStat> entry_stat,
1246     scoped_ptr<int> result) {
1247   if (*result >= 0)
1248     RecordWriteResult(cache_type_, WRITE_RESULT_SUCCESS);
1249   else
1250     RecordWriteResult(cache_type_, WRITE_RESULT_SYNC_WRITE_FAILURE);
1251   if (net_log_.IsLogging()) {
1252     net_log_.AddEvent(net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_WRITE_END,
1253         CreateNetLogReadWriteCompleteCallback(*result));
1254   }
1255 
1256   if (*result < 0) {
1257     crc32s_end_offset_[stream_index] = 0;
1258   }
1259 
1260   EntryOperationComplete(completion_callback, *entry_stat, result.Pass());
1261 }
1262 
ReadSparseOperationComplete(const CompletionCallback & completion_callback,scoped_ptr<base::Time> last_used,scoped_ptr<int> result)1263 void SimpleEntryImpl::ReadSparseOperationComplete(
1264     const CompletionCallback& completion_callback,
1265     scoped_ptr<base::Time> last_used,
1266     scoped_ptr<int> result) {
1267   DCHECK(io_thread_checker_.CalledOnValidThread());
1268   DCHECK(synchronous_entry_);
1269   DCHECK(result);
1270 
1271   SimpleEntryStat entry_stat(*last_used, last_modified_, data_size_,
1272                              sparse_data_size_);
1273   EntryOperationComplete(completion_callback, entry_stat, result.Pass());
1274 }
1275 
WriteSparseOperationComplete(const CompletionCallback & completion_callback,scoped_ptr<SimpleEntryStat> entry_stat,scoped_ptr<int> result)1276 void SimpleEntryImpl::WriteSparseOperationComplete(
1277     const CompletionCallback& completion_callback,
1278     scoped_ptr<SimpleEntryStat> entry_stat,
1279     scoped_ptr<int> result) {
1280   DCHECK(io_thread_checker_.CalledOnValidThread());
1281   DCHECK(synchronous_entry_);
1282   DCHECK(result);
1283 
1284   EntryOperationComplete(completion_callback, *entry_stat, result.Pass());
1285 }
1286 
GetAvailableRangeOperationComplete(const CompletionCallback & completion_callback,scoped_ptr<int> result)1287 void SimpleEntryImpl::GetAvailableRangeOperationComplete(
1288     const CompletionCallback& completion_callback,
1289     scoped_ptr<int> result) {
1290   DCHECK(io_thread_checker_.CalledOnValidThread());
1291   DCHECK(synchronous_entry_);
1292   DCHECK(result);
1293 
1294   SimpleEntryStat entry_stat(last_used_, last_modified_, data_size_,
1295                              sparse_data_size_);
1296   EntryOperationComplete(completion_callback, entry_stat, result.Pass());
1297 }
1298 
DoomOperationComplete(const CompletionCallback & callback,State state_to_restore,int result)1299 void SimpleEntryImpl::DoomOperationComplete(
1300     const CompletionCallback& callback,
1301     State state_to_restore,
1302     int result) {
1303   state_ = state_to_restore;
1304   net_log_.AddEvent(net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_DOOM_END);
1305   if (!callback.is_null())
1306     callback.Run(result);
1307   RunNextOperationIfNeeded();
1308   if (backend_)
1309     backend_->OnDoomComplete(entry_hash_);
1310 }
1311 
ChecksumOperationComplete(int orig_result,int stream_index,const CompletionCallback & completion_callback,scoped_ptr<int> result)1312 void SimpleEntryImpl::ChecksumOperationComplete(
1313     int orig_result,
1314     int stream_index,
1315     const CompletionCallback& completion_callback,
1316     scoped_ptr<int> result) {
1317   DCHECK(io_thread_checker_.CalledOnValidThread());
1318   DCHECK(synchronous_entry_);
1319   DCHECK_EQ(STATE_IO_PENDING, state_);
1320   DCHECK(result);
1321 
1322   if (net_log_.IsLogging()) {
1323     net_log_.AddEventWithNetErrorCode(
1324         net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_CHECKSUM_END,
1325         *result);
1326   }
1327 
1328   if (*result == net::OK) {
1329     *result = orig_result;
1330     if (orig_result >= 0)
1331       RecordReadResult(cache_type_, READ_RESULT_SUCCESS);
1332     else
1333       RecordReadResult(cache_type_, READ_RESULT_SYNC_READ_FAILURE);
1334   } else {
1335     RecordReadResult(cache_type_, READ_RESULT_SYNC_CHECKSUM_FAILURE);
1336   }
1337   if (net_log_.IsLogging()) {
1338     net_log_.AddEvent(net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_READ_END,
1339         CreateNetLogReadWriteCompleteCallback(*result));
1340   }
1341 
1342   SimpleEntryStat entry_stat(last_used_, last_modified_, data_size_,
1343                              sparse_data_size_);
1344   EntryOperationComplete(completion_callback, entry_stat, result.Pass());
1345 }
1346 
CloseOperationComplete()1347 void SimpleEntryImpl::CloseOperationComplete() {
1348   DCHECK(!synchronous_entry_);
1349   DCHECK_EQ(0, open_count_);
1350   DCHECK(STATE_IO_PENDING == state_ || STATE_FAILURE == state_ ||
1351          STATE_UNINITIALIZED == state_);
1352   net_log_.AddEvent(net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_CLOSE_END);
1353   AdjustOpenEntryCountBy(cache_type_, -1);
1354   MakeUninitialized();
1355   RunNextOperationIfNeeded();
1356 }
1357 
UpdateDataFromEntryStat(const SimpleEntryStat & entry_stat)1358 void SimpleEntryImpl::UpdateDataFromEntryStat(
1359     const SimpleEntryStat& entry_stat) {
1360   DCHECK(io_thread_checker_.CalledOnValidThread());
1361   DCHECK(synchronous_entry_);
1362   DCHECK_EQ(STATE_READY, state_);
1363 
1364   last_used_ = entry_stat.last_used();
1365   last_modified_ = entry_stat.last_modified();
1366   for (int i = 0; i < kSimpleEntryStreamCount; ++i) {
1367     data_size_[i] = entry_stat.data_size(i);
1368   }
1369   sparse_data_size_ = entry_stat.sparse_data_size();
1370   if (!doomed_ && backend_.get())
1371     backend_->index()->UpdateEntrySize(entry_hash_, GetDiskUsage());
1372 }
1373 
GetDiskUsage() const1374 int64 SimpleEntryImpl::GetDiskUsage() const {
1375   int64 file_size = 0;
1376   for (int i = 0; i < kSimpleEntryStreamCount; ++i) {
1377     file_size +=
1378         simple_util::GetFileSizeFromKeyAndDataSize(key_, data_size_[i]);
1379   }
1380   file_size += sparse_data_size_;
1381   return file_size;
1382 }
1383 
RecordReadIsParallelizable(const SimpleEntryOperation & operation) const1384 void SimpleEntryImpl::RecordReadIsParallelizable(
1385     const SimpleEntryOperation& operation) const {
1386   if (!executing_operation_)
1387     return;
1388   // Used in histograms, please only add entries at the end.
1389   enum ReadDependencyType {
1390     // READ_STANDALONE = 0, Deprecated.
1391     READ_FOLLOWS_READ = 1,
1392     READ_FOLLOWS_CONFLICTING_WRITE = 2,
1393     READ_FOLLOWS_NON_CONFLICTING_WRITE = 3,
1394     READ_FOLLOWS_OTHER = 4,
1395     READ_ALONE_IN_QUEUE = 5,
1396     READ_DEPENDENCY_TYPE_MAX = 6,
1397   };
1398 
1399   ReadDependencyType type = READ_FOLLOWS_OTHER;
1400   if (operation.alone_in_queue()) {
1401     type = READ_ALONE_IN_QUEUE;
1402   } else if (executing_operation_->type() == SimpleEntryOperation::TYPE_READ) {
1403     type = READ_FOLLOWS_READ;
1404   } else if (executing_operation_->type() == SimpleEntryOperation::TYPE_WRITE) {
1405     if (executing_operation_->ConflictsWith(operation))
1406       type = READ_FOLLOWS_CONFLICTING_WRITE;
1407     else
1408       type = READ_FOLLOWS_NON_CONFLICTING_WRITE;
1409   }
1410   SIMPLE_CACHE_UMA(ENUMERATION,
1411                    "ReadIsParallelizable", cache_type_,
1412                    type, READ_DEPENDENCY_TYPE_MAX);
1413 }
1414 
RecordWriteDependencyType(const SimpleEntryOperation & operation) const1415 void SimpleEntryImpl::RecordWriteDependencyType(
1416     const SimpleEntryOperation& operation) const {
1417   if (!executing_operation_)
1418     return;
1419   // Used in histograms, please only add entries at the end.
1420   enum WriteDependencyType {
1421     WRITE_OPTIMISTIC = 0,
1422     WRITE_FOLLOWS_CONFLICTING_OPTIMISTIC = 1,
1423     WRITE_FOLLOWS_NON_CONFLICTING_OPTIMISTIC = 2,
1424     WRITE_FOLLOWS_CONFLICTING_WRITE = 3,
1425     WRITE_FOLLOWS_NON_CONFLICTING_WRITE = 4,
1426     WRITE_FOLLOWS_CONFLICTING_READ = 5,
1427     WRITE_FOLLOWS_NON_CONFLICTING_READ = 6,
1428     WRITE_FOLLOWS_OTHER = 7,
1429     WRITE_DEPENDENCY_TYPE_MAX = 8,
1430   };
1431 
1432   WriteDependencyType type = WRITE_FOLLOWS_OTHER;
1433   if (operation.optimistic()) {
1434     type = WRITE_OPTIMISTIC;
1435   } else if (executing_operation_->type() == SimpleEntryOperation::TYPE_READ ||
1436              executing_operation_->type() == SimpleEntryOperation::TYPE_WRITE) {
1437     bool conflicting = executing_operation_->ConflictsWith(operation);
1438 
1439     if (executing_operation_->type() == SimpleEntryOperation::TYPE_READ) {
1440       type = conflicting ? WRITE_FOLLOWS_CONFLICTING_READ
1441                          : WRITE_FOLLOWS_NON_CONFLICTING_READ;
1442     } else if (executing_operation_->optimistic()) {
1443       type = conflicting ? WRITE_FOLLOWS_CONFLICTING_OPTIMISTIC
1444                          : WRITE_FOLLOWS_NON_CONFLICTING_OPTIMISTIC;
1445     } else {
1446       type = conflicting ? WRITE_FOLLOWS_CONFLICTING_WRITE
1447                          : WRITE_FOLLOWS_NON_CONFLICTING_WRITE;
1448     }
1449   }
1450   SIMPLE_CACHE_UMA(ENUMERATION,
1451                    "WriteDependencyType", cache_type_,
1452                    type, WRITE_DEPENDENCY_TYPE_MAX);
1453 }
1454 
ReadStream0Data(net::IOBuffer * buf,int offset,int buf_len)1455 int SimpleEntryImpl::ReadStream0Data(net::IOBuffer* buf,
1456                                      int offset,
1457                                      int buf_len) {
1458   if (buf_len < 0) {
1459     RecordReadResult(cache_type_, READ_RESULT_SYNC_READ_FAILURE);
1460     return 0;
1461   }
1462   memcpy(buf->data(), stream_0_data_->data() + offset, buf_len);
1463   UpdateDataFromEntryStat(
1464       SimpleEntryStat(base::Time::Now(), last_modified_, data_size_,
1465                       sparse_data_size_));
1466   RecordReadResult(cache_type_, READ_RESULT_SUCCESS);
1467   return buf_len;
1468 }
1469 
SetStream0Data(net::IOBuffer * buf,int offset,int buf_len,bool truncate)1470 int SimpleEntryImpl::SetStream0Data(net::IOBuffer* buf,
1471                                     int offset,
1472                                     int buf_len,
1473                                     bool truncate) {
1474   // Currently, stream 0 is only used for HTTP headers, and always writes them
1475   // with a single, truncating write. Detect these writes and record the size
1476   // changes of the headers. Also, support writes to stream 0 that have
1477   // different access patterns, as required by the API contract.
1478   // All other clients of the Simple Cache are encouraged to use stream 1.
1479   have_written_[0] = true;
1480   int data_size = GetDataSize(0);
1481   if (offset == 0 && truncate) {
1482     RecordHeaderSizeChange(cache_type_, data_size, buf_len);
1483     stream_0_data_->SetCapacity(buf_len);
1484     memcpy(stream_0_data_->data(), buf->data(), buf_len);
1485     data_size_[0] = buf_len;
1486   } else {
1487     RecordUnexpectedStream0Write(cache_type_);
1488     const int buffer_size =
1489         truncate ? offset + buf_len : std::max(offset + buf_len, data_size);
1490     stream_0_data_->SetCapacity(buffer_size);
1491     // If |stream_0_data_| was extended, the extension until offset needs to be
1492     // zero-filled.
1493     const int fill_size = offset <= data_size ? 0 : offset - data_size;
1494     if (fill_size > 0)
1495       memset(stream_0_data_->data() + data_size, 0, fill_size);
1496     if (buf)
1497       memcpy(stream_0_data_->data() + offset, buf->data(), buf_len);
1498     data_size_[0] = buffer_size;
1499   }
1500   base::Time modification_time = base::Time::Now();
1501   AdvanceCrc(buf, offset, buf_len, 0);
1502   UpdateDataFromEntryStat(
1503       SimpleEntryStat(modification_time, modification_time, data_size_,
1504                       sparse_data_size_));
1505   RecordWriteResult(cache_type_, WRITE_RESULT_SUCCESS);
1506   return buf_len;
1507 }
1508 
AdvanceCrc(net::IOBuffer * buffer,int offset,int length,int stream_index)1509 void SimpleEntryImpl::AdvanceCrc(net::IOBuffer* buffer,
1510                                  int offset,
1511                                  int length,
1512                                  int stream_index) {
1513   // It is easy to incrementally compute the CRC from [0 .. |offset + buf_len|)
1514   // if |offset == 0| or we have already computed the CRC for [0 .. offset).
1515   // We rely on most write operations being sequential, start to end to compute
1516   // the crc of the data. When we write to an entry and close without having
1517   // done a sequential write, we don't check the CRC on read.
1518   if (offset == 0 || crc32s_end_offset_[stream_index] == offset) {
1519     uint32 initial_crc =
1520         (offset != 0) ? crc32s_[stream_index] : crc32(0, Z_NULL, 0);
1521     if (length > 0) {
1522       crc32s_[stream_index] = crc32(
1523           initial_crc, reinterpret_cast<const Bytef*>(buffer->data()), length);
1524     }
1525     crc32s_end_offset_[stream_index] = offset + length;
1526   } else if (offset < crc32s_end_offset_[stream_index]) {
1527     // If a range for which the crc32 was already computed is rewritten, the
1528     // computation of the crc32 need to start from 0 again.
1529     crc32s_end_offset_[stream_index] = 0;
1530   }
1531 }
1532 
1533 }  // namespace disk_cache
1534