| Index: net/disk_cache/simple/simple_entry_impl.cc | 
| diff --git a/net/disk_cache/simple/simple_entry_impl.cc b/net/disk_cache/simple/simple_entry_impl.cc | 
| index 8ab8e2ea4e9857c8c7eb3c8f1738b4d9de04f42d..0e860d70664132df34f7b3b5405f3532168c52b7 100644 | 
| --- a/net/disk_cache/simple/simple_entry_impl.cc | 
| +++ b/net/disk_cache/simple/simple_entry_impl.cc | 
| @@ -179,6 +179,7 @@ SimpleEntryImpl::SimpleEntryImpl( | 
| path_(path), | 
| entry_hash_(entry_hash), | 
| use_optimistic_operations_(operations_mode == OPTIMISTIC_OPERATIONS), | 
| +      is_initial_stream1_read_(true), | 
| last_used_(Time::Now()), | 
| last_modified_(last_used_), | 
| sparse_data_size_(0), | 
| @@ -550,7 +551,8 @@ size_t SimpleEntryImpl::EstimateMemoryUsage() const { | 
| return sizeof(SimpleSynchronousEntry) + | 
| base::trace_event::EstimateMemoryUsage(pending_operations_) + | 
| base::trace_event::EstimateMemoryUsage(executing_operation_) + | 
| -         (stream_0_data_ ? stream_0_data_->capacity() : 0); | 
| +         (stream_0_data_ ? stream_0_data_->capacity() : 0) + | 
| +         (stream_1_prefetch_data_ ? stream_1_prefetch_data_->capacity() : 0); | 
| } | 
|  | 
| SimpleEntryImpl::~SimpleEntryImpl() { | 
| @@ -851,14 +853,26 @@ void SimpleEntryImpl::ReadDataInternal(int stream_index, | 
|  | 
| // Since stream 0 data is kept in memory, it is read immediately. | 
| if (stream_index == 0) { | 
| -    int ret_value = ReadStream0Data(buf, offset, buf_len); | 
| -    if (!callback.is_null()) { | 
| -      base::ThreadTaskRunnerHandle::Get()->PostTask( | 
| -          FROM_HERE, base::Bind(callback, ret_value)); | 
| -    } | 
| +    ReadFromBufferAndPostReply(stream_0_data_.get(), offset, buf_len, buf, | 
| +                               callback); | 
| return; | 
| } | 
|  | 
| +  // Sometimes we can read in-ram prefetched stream 1 data immediately, too. | 
| +  if (stream_index == 1) { | 
| +    if (is_initial_stream1_read_) { | 
| +      SIMPLE_CACHE_UMA(BOOLEAN, "ReadStream1FromPrefetched", cache_type_, | 
| +                       stream_1_prefetch_data_ != nullptr); | 
| +    } | 
| +    is_initial_stream1_read_ = false; | 
| + | 
| +    if (stream_1_prefetch_data_) { | 
| +      ReadFromBufferAndPostReply(stream_1_prefetch_data_.get(), offset, buf_len, | 
| +                                 buf, callback); | 
| +      return; | 
| +    } | 
| +  } | 
| + | 
| state_ = STATE_IO_PENDING; | 
| if (!doomed_ && backend_.get()) | 
| backend_->index()->UseIfExists(entry_hash_); | 
| @@ -950,6 +964,10 @@ void SimpleEntryImpl::WriteDataInternal(int stream_index, | 
| if (!doomed_ && backend_.get()) | 
| backend_->index()->UseIfExists(entry_hash_); | 
|  | 
| +  // Any stream 1 write invalidates the prefetched data. | 
| +  if (stream_index == 1) | 
| +    stream_1_prefetch_data_ = nullptr; | 
| + | 
| AdvanceCrc(buf, offset, buf_len, stream_index); | 
|  | 
| // |entry_stat| needs to be initialized before modifying |data_size_|. | 
| @@ -1147,13 +1165,24 @@ void SimpleEntryImpl::CreationOperationComplete( | 
|  | 
| state_ = STATE_READY; | 
| synchronous_entry_ = in_results->sync_entry; | 
| -  if (in_results->stream_0_data.get()) { | 
| -    stream_0_data_ = in_results->stream_0_data; | 
| -    // The crc was read in SimpleSynchronousEntry. | 
| -    crc_check_state_[0] = CRC_CHECK_DONE; | 
| -    crc32s_[0] = in_results->stream_0_crc32; | 
| -    crc32s_end_offset_[0] = in_results->entry_stat.data_size(0); | 
| + | 
| +  // Copy over any pre-fetched data and its CRCs. | 
| +  for (int stream = 0; stream < 2; ++stream) { | 
| +    const SimpleStreamPrefetchData& prefetched = | 
| +        in_results->stream_prefetch_data[stream]; | 
| +    if (prefetched.data.get()) { | 
| +      if (stream == 0) | 
| +        stream_0_data_ = prefetched.data; | 
| +      else | 
| +        stream_1_prefetch_data_ = prefetched.data; | 
| + | 
| +      // The crc was read in SimpleSynchronousEntry. | 
| +      crc_check_state_[stream] = CRC_CHECK_DONE; | 
| +      crc32s_[stream] = prefetched.stream_crc32; | 
| +      crc32s_end_offset_[stream] = in_results->entry_stat.data_size(stream); | 
| +    } | 
| } | 
| + | 
| // If this entry was opened by hash, key_ could still be empty. If so, update | 
| // it with the key read from the synchronous entry. | 
| if (key_.empty()) { | 
| @@ -1449,19 +1478,27 @@ void SimpleEntryImpl::RecordWriteDependencyType( | 
| type, WRITE_DEPENDENCY_TYPE_MAX); | 
| } | 
|  | 
| -int SimpleEntryImpl::ReadStream0Data(net::IOBuffer* buf, | 
| -                                     int offset, | 
| -                                     int buf_len) { | 
| +void SimpleEntryImpl::ReadFromBufferAndPostReply( | 
| +    net::GrowableIOBuffer* in_buf, | 
| +    int offset, | 
| +    int buf_len, | 
| +    net::IOBuffer* out_buf, | 
| +    const CompletionCallback& callback) { | 
| +  int rv; | 
| if (buf_len < 0) { | 
| RecordReadResult(cache_type_, READ_RESULT_SYNC_READ_FAILURE); | 
| -    return 0; | 
| +    rv = 0; | 
| +  } else { | 
| +    memcpy(out_buf->data(), in_buf->data() + offset, buf_len); | 
| +    UpdateDataFromEntryStat(SimpleEntryStat(base::Time::Now(), last_modified_, | 
| +                                            data_size_, sparse_data_size_)); | 
| +    RecordReadResult(cache_type_, READ_RESULT_SUCCESS); | 
| +    rv = buf_len; | 
| +  } | 
| +  if (!callback.is_null()) { | 
| +    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, | 
| +                                                  base::Bind(callback, rv)); | 
| } | 
| -  memcpy(buf->data(), stream_0_data_->data() + offset, buf_len); | 
| -  UpdateDataFromEntryStat( | 
| -      SimpleEntryStat(base::Time::Now(), last_modified_, data_size_, | 
| -                      sparse_data_size_)); | 
| -  RecordReadResult(cache_type_, READ_RESULT_SUCCESS); | 
| -  return buf_len; | 
| } | 
|  | 
| int SimpleEntryImpl::SetStream0Data(net::IOBuffer* buf, | 
|  |